From e86ac5875adbfdee8a2fbaff92f3126a87bae502 Mon Sep 17 00:00:00 2001 From: nate smith Date: Sun, 30 Apr 2023 23:19:20 -0700 Subject: [PATCH] towards exits, provides --- roadmap.md | 20 ++++++++++++++++++++ server/db/db.go | 5 +---- server/witch/header.go | 25 ++++++++++++++++++++++++- server/witch/witch.go | 24 ++++++++++++++++++++++++ 4 files changed, 69 insertions(+), 5 deletions(-) diff --git a/roadmap.md b/roadmap.md index b34a13f..46a684f 100644 --- a/roadmap.md +++ b/roadmap.md @@ -47,6 +47,26 @@ aside: i want to think through why exits shouldn't be on a room but it's a prett so i'm going back to the tildemush approach. the next question is; is the exit maps a useful thing? couldn't the go handler just add a second, mirrored go handler? a handler that checks room directionality? +i've added a WITCH function, goes, which takes a direction and two rooms. this WITCH function adds two `go` verb handlers--one for the direction in the `goes` invocation and then one for the reverse. i like this more than the exit map, but it does mean that exits could compete each other. can't remember if that could happen in tildemush (was the exits map stored per exit? was that guarded?). + +i think the competing is fine. i'm actually fine with it. i think that goes() could also add an invocation of `provides()` like this: + +```lua +provides("use $this", function(args) + move_sender("target_room") +end) +``` + +A nice idea is the ability for an exit to add flavor to an entity transitioning through it; for this I can maybe add: + +```lua +goesAnd(east, "ossuary", "gallery", function(args) + tellSender("the door squeals harshly as you move it but allows you passage") +end) +``` + +The movement is still generated. + ## server beta - [x] grpc server diff --git a/server/db/db.go b/server/db/db.go index 5891214..b72c953 100644 --- a/server/db/db.go +++ b/server/db/db.go @@ -176,10 +176,7 @@ func (db *pgDB) Ensure() error { oakDoor = &Object{ Data: data, Script: ` - go("north", function() - tellSender("the heavy door swings forward with ease. It creaks gently") - moveSender("system", "pub") - end) + goes(north, "pub") `, } if err = db.CreateObject(sysAcc, oakDoor); err != nil { diff --git a/server/witch/header.go b/server/witch/header.go index bbd5cc6..c80048c 100644 --- a/server/witch/header.go +++ b/server/witch/header.go @@ -1,6 +1,16 @@ package witch +/* + +This file contains the definitions of functions that are injected into scope for WITCH scripts. See witch.go's ScriptContext to see how they are actually added to a LuaState. + +TODO: consider making this (or witch.go) a different package entirely. the `witch` prefix for the function names in this file is a little annoying. + +*/ + import ( + "strings" + lua "github.com/yuin/gopher-lua" ) @@ -9,7 +19,20 @@ func witchHas(l *lua.LState) int { return 0 } -// TODO provides +func witchProvides(l *lua.LState) int { + // TODO test this manually + + verbAndPattern := l.ToString(1) + l.Pop(1) + + split := strings.SplitN(verbAndPattern, " ", 2) + verb := split[0] + pattern := split[1] + + l.Push(lua.LString(pattern)) + + return addPatternHandler(l, verb) +} func witchHears(l *lua.LState) int { return addPatternHandler(l, "say") diff --git a/server/witch/witch.go b/server/witch/witch.go index 5d5a99f..847a793 100644 --- a/server/witch/witch.go +++ b/server/witch/witch.go @@ -1,5 +1,11 @@ package witch +/* + +This file is the interface between the game server and WITCH execution + +*/ + import ( "fmt" "log" @@ -127,18 +133,36 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage) // TODO clear this object out of the exits table sc.script = vc.Target.Script l = lua.NewState() + + // direction constants + l.SetGlobal("east", lua.LString("_DIR_EAST")) + l.SetGlobal("west", lua.LString("_DIR_WEST")) + l.SetGlobal("north", lua.LString("_DIR_NORTH")) + l.SetGlobal("south", lua.LString("_DIR_SOUTH")) + l.SetGlobal("above", lua.LString("_DIR_ABOVE")) + l.SetGlobal("below", lua.LString("_DIR_BELOW")) + l.SetGlobal("up", lua.LString("_DIR_ABOVE")) + l.SetGlobal("down", lua.LString("_DIR_BELOW")) + + // witch object behavior functions l.SetGlobal("has", l.NewFunction(witchHas)) l.SetGlobal("hears", l.NewFunction(witchHears)) l.SetGlobal("sees", l.NewFunction(witchSees)) l.SetGlobal("goes", l.NewFunction(witchGoes)) l.SetGlobal("seen", l.NewFunction(witchSeen)) l.SetGlobal("my", l.NewFunction(witchMy)) + l.SetGlobal("provides", l.NewFunction(witchProvides)) + + // witch helpers l.SetGlobal("_handlers", l.NewTable()) + if err := l.DoString(vc.Target.Script); err != nil { log.Printf("error parsing script %s: %s", vc.Target.Script, err.Error()) } } + // witch action functions relative to calling context + l.SetGlobal("tellMe", l.NewFunction(func(l *lua.LState) int { sender := l.GetGlobal("sender").(*lua.LTable) senderID := int(lua.LVAsNumber(sender.RawGetString("ID")))