one way exits
parent
3bb94c490e
commit
84cfc0f12d
31
roadmap.md
31
roadmap.md
|
@ -67,6 +67,37 @@ end)
|
||||||
|
|
||||||
The movement is still generated.
|
The movement is still generated.
|
||||||
|
|
||||||
|
|
||||||
|
so the problem with all of this is that the beahvior of the exit is
|
||||||
|
supposedly going to change based on how it is contained. however, we only
|
||||||
|
re-read the code when the code changes. we're trying to affect game state
|
||||||
|
as part of code compilation and that's uncool.
|
||||||
|
|
||||||
|
a user would create a new exit, put all the finishing touches on it, then move
|
||||||
|
it from their person to the room the exit originates from. WITCH would not
|
||||||
|
recompile and no containership would update.
|
||||||
|
|
||||||
|
i think the dream of goes(north, "pub") is donezo. i think the next best
|
||||||
|
thing is goes(north, "foyer", "pub"). on execution, the sender is checked;
|
||||||
|
if their container is the first room then they are moved to the second
|
||||||
|
room. both cases suffer from the double containment problem. that second
|
||||||
|
containment *cannot* be updated as part of WITCH compilation.
|
||||||
|
|
||||||
|
so we're back to two options:
|
||||||
|
- one way exits
|
||||||
|
- special creation semantics that handle something like double containership
|
||||||
|
|
||||||
|
in the interest of moving on--and of putting off special top level commands
|
||||||
|
that exist outside of WITCH--i want to do one way exits for now. this sucks
|
||||||
|
because all the flavor written for an exit has to be duplicated for its pair.
|
||||||
|
|
||||||
|
some other ideas because i can't let go. what of a variation on the exits map
|
||||||
|
where each exit stores a key in its has data about where it goes. this is no
|
||||||
|
better than a dynamic handler (it's worse) and does not help the double
|
||||||
|
containership problem.
|
||||||
|
|
||||||
|
give up and do one way exits.
|
||||||
|
|
||||||
## server beta
|
## server beta
|
||||||
|
|
||||||
- [x] grpc server
|
- [x] grpc server
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/jackc/pgx/v4/pgxpool"
|
"github.com/jackc/pgx/v4/pgxpool"
|
||||||
|
@ -30,6 +31,7 @@ type DB interface {
|
||||||
// General
|
// General
|
||||||
GetObject(owner, name string) (*Object, error)
|
GetObject(owner, name string) (*Object, error)
|
||||||
GetObjectByID(ID int) (*Object, error)
|
GetObjectByID(ID int) (*Object, error)
|
||||||
|
SearchObjectsByName(term string) ([]Object, error)
|
||||||
|
|
||||||
// Defaults
|
// Defaults
|
||||||
Ensure() error
|
Ensure() error
|
||||||
|
@ -41,7 +43,8 @@ type DB interface {
|
||||||
AvatarBySessionID(string) (*Object, error)
|
AvatarBySessionID(string) (*Object, error)
|
||||||
BedroomBySessionID(string) (*Object, error)
|
BedroomBySessionID(string) (*Object, error)
|
||||||
MoveInto(toMove Object, container Object) error
|
MoveInto(toMove Object, container Object) error
|
||||||
Earshot(Object) ([]Object, error)
|
Earshot(vantage Object) ([]Object, error)
|
||||||
|
Resolve(vantage Object, term string) ([]Object, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
|
@ -488,6 +491,54 @@ func (db *pgDB) GetObject(owner, name string) (obj *Object, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *pgDB) SearchObjectsByName(term string) ([]Object, error) {
|
||||||
|
ctx := context.Background()
|
||||||
|
|
||||||
|
stmt := `
|
||||||
|
SELECT id, avatar, data, owner, script
|
||||||
|
FROM objects
|
||||||
|
WHERE data['name']::varchar LIKE $1
|
||||||
|
`
|
||||||
|
|
||||||
|
rows, err := db.pool.Query(ctx, stmt, "%"+term+"%")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := []Object{}
|
||||||
|
for rows.Next() {
|
||||||
|
o := Object{}
|
||||||
|
if err = rows.Scan(
|
||||||
|
&o.ID,
|
||||||
|
&o.Avatar,
|
||||||
|
&o.Data,
|
||||||
|
&o.OwnerID,
|
||||||
|
&o.Script); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out = append(out, o)
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *pgDB) Resolve(vantage Object, term string) ([]Object, error) {
|
||||||
|
stuff, err := db.Earshot(vantage)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := []Object{}
|
||||||
|
|
||||||
|
for _, o := range stuff {
|
||||||
|
if strings.Contains(o.Data["name"], term) {
|
||||||
|
out = append(out, o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (db *pgDB) GetAccountAvatar(account Account) (*Object, error) {
|
func (db *pgDB) GetAccountAvatar(account Account) (*Object, error) {
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
obj := &Object{
|
obj := &Object{
|
||||||
|
|
|
@ -39,9 +39,3 @@ CREATE TABLE contains (
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TYPE heading AS ENUM ('north', 'south', 'east', 'west', 'above', 'below');
|
CREATE TYPE heading AS ENUM ('north', 'south', 'east', 'west', 'above', 'below');
|
||||||
|
|
||||||
CREATE TABLE exits (
|
|
||||||
startroom integer REFERENCES objects ON DELETE CASCADE,
|
|
||||||
endroom integer REFERENCES objects ON DELETE CASCADE,
|
|
||||||
direction heading NOT NULL
|
|
||||||
);
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package witch
|
package witch
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
dirEast = "_DIR_EAST"
|
dirEast = "_DIR_EAST"
|
||||||
dirWest = "_DIR_WEST"
|
dirWest = "_DIR_WEST"
|
||||||
|
@ -13,6 +15,10 @@ type Direction struct {
|
||||||
raw string
|
raw string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDirection(raw string) Direction {
|
||||||
|
return Direction{raw: raw}
|
||||||
|
}
|
||||||
|
|
||||||
func (d Direction) Reverse() Direction {
|
func (d Direction) Reverse() Direction {
|
||||||
raw := ""
|
raw := ""
|
||||||
switch d.raw {
|
switch d.raw {
|
||||||
|
@ -29,11 +35,11 @@ func (d Direction) Reverse() Direction {
|
||||||
case dirSouth:
|
case dirSouth:
|
||||||
raw = dirNorth
|
raw = dirNorth
|
||||||
}
|
}
|
||||||
return Direction{raw: raw}
|
return NewDirection(raw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NormalizeHuman takes a direction someone might type like "up" or "north" and returns the correct Direction struct
|
// NormalizeDirection takes a direction someone might type like "up" or "north" and returns the correct Direction struct
|
||||||
func NormalizeHuman(humanDir string) Direction {
|
func NormalizeDirection(humanDir string) (Direction, error) {
|
||||||
raw := ""
|
raw := ""
|
||||||
switch humanDir {
|
switch humanDir {
|
||||||
case "up":
|
case "up":
|
||||||
|
@ -50,9 +56,11 @@ func NormalizeHuman(humanDir string) Direction {
|
||||||
raw = dirNorth
|
raw = dirNorth
|
||||||
case "south":
|
case "south":
|
||||||
raw = dirSouth
|
raw = dirSouth
|
||||||
|
default:
|
||||||
|
return Direction{}, fmt.Errorf("did not understand direction '%s'", humanDir)
|
||||||
}
|
}
|
||||||
return Direction{raw: raw}
|
|
||||||
|
return NewDirection(raw), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Human returns a string form of this direction like "above" or "north"
|
// Human returns a string form of this direction like "above" or "north"
|
||||||
|
@ -74,3 +82,7 @@ func (d Direction) Human() (humanDir string) {
|
||||||
|
|
||||||
return humanDir
|
return humanDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d Direction) Equals(o Direction) bool {
|
||||||
|
return d.raw == o.raw
|
||||||
|
}
|
||||||
|
|
|
@ -1,116 +0,0 @@
|
||||||
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 (
|
|
||||||
"log"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
lua "github.com/yuin/gopher-lua"
|
|
||||||
)
|
|
||||||
|
|
||||||
func witchHas(l *lua.LState) int {
|
|
||||||
l.SetGlobal("_has", l.ToTable(1))
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchProvides(l *lua.LState) int {
|
|
||||||
// TODO test this manually
|
|
||||||
|
|
||||||
verbAndPattern := l.ToString(1)
|
|
||||||
cb := l.ToFunction(2)
|
|
||||||
|
|
||||||
split := strings.SplitN(verbAndPattern, " ", 2)
|
|
||||||
verb := split[0]
|
|
||||||
pattern := split[1]
|
|
||||||
|
|
||||||
return addPatternHandler(l, verb, pattern, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchHears(l *lua.LState) int {
|
|
||||||
pattern := l.ToString(1)
|
|
||||||
cb := l.ToFunction(2)
|
|
||||||
return addPatternHandler(l, "say", pattern, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchSees(l *lua.LState) int {
|
|
||||||
pattern := l.ToString(1)
|
|
||||||
cb := l.ToFunction(2)
|
|
||||||
|
|
||||||
return addPatternHandler(l, "emote", pattern, cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchGoes(l *lua.LState) int {
|
|
||||||
// TODO validate direction
|
|
||||||
// TODO convert direction constant to english
|
|
||||||
|
|
||||||
direction := l.ToString(1)
|
|
||||||
targetRoom := l.ToString(2)
|
|
||||||
|
|
||||||
cb := func(l *lua.LState) int {
|
|
||||||
log.Printf("please move sender to target room '%s'", targetRoom)
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO call addPatternHandler again for the reverse direction (make a reverse helper)
|
|
||||||
return addPatternHandler(l, "go", direction, l.NewFunction(cb))
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchSeen(l *lua.LState) int {
|
|
||||||
cb := l.ToFunction(1)
|
|
||||||
return addHandler(l, "look", cb)
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchMy(l *lua.LState) int {
|
|
||||||
hasT := l.GetGlobal("_has").(*lua.LTable)
|
|
||||||
val := hasT.RawGetString(l.ToString(1))
|
|
||||||
l.Push(val)
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
func witchDoes(ls *lua.LState) int {
|
|
||||||
// TODO how to feed events back into the server?
|
|
||||||
// it needs to behave like an event showing up in Commands stream
|
|
||||||
// this handler needs a reference to the gateway which has a channel for sending events that the server will see?
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func addHandler(l *lua.LState, verb string, cb *lua.LFunction) int {
|
|
||||||
pattern := ".*"
|
|
||||||
|
|
||||||
log.Printf("adding handler: %s %s %#v", verb, pattern, cb)
|
|
||||||
|
|
||||||
handlers := l.GetGlobal("_handlers").(*lua.LTable)
|
|
||||||
|
|
||||||
verbHandlers, ok := handlers.RawGetString(verb).(*lua.LTable)
|
|
||||||
if !ok {
|
|
||||||
verbHandlers = l.NewTable()
|
|
||||||
handlers.RawSetString(verb, verbHandlers)
|
|
||||||
}
|
|
||||||
|
|
||||||
verbHandlers.RawSetString(pattern, cb)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func addPatternHandler(l *lua.LState, verb, pattern string, cb *lua.LFunction) int {
|
|
||||||
log.Printf("adding handler: %s %s %#v", verb, string(pattern), cb)
|
|
||||||
|
|
||||||
handlers := l.GetGlobal("_handlers").(*lua.LTable)
|
|
||||||
|
|
||||||
verbHandlers, ok := handlers.RawGetString(verb).(*lua.LTable)
|
|
||||||
if !ok {
|
|
||||||
verbHandlers = l.NewTable()
|
|
||||||
handlers.RawSetString(verb, verbHandlers)
|
|
||||||
}
|
|
||||||
|
|
||||||
verbHandlers.RawSetString(pattern, cb)
|
|
||||||
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/vilmibm/hermeticum/proto"
|
"github.com/vilmibm/hermeticum/proto"
|
||||||
"github.com/vilmibm/hermeticum/server/db"
|
"github.com/vilmibm/hermeticum/server/db"
|
||||||
|
@ -120,6 +121,7 @@ type ScriptContext struct {
|
||||||
func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage) error) (*ScriptContext, error) {
|
func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage) error) (*ScriptContext, error) {
|
||||||
sc := &ScriptContext{
|
sc := &ScriptContext{
|
||||||
serverAPI: serverAPI{db: db, getSend: getSend},
|
serverAPI: serverAPI{db: db, getSend: getSend},
|
||||||
|
db: db,
|
||||||
}
|
}
|
||||||
sc.incoming = make(chan VerbContext)
|
sc.incoming = make(chan VerbContext)
|
||||||
|
|
||||||
|
@ -130,7 +132,6 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage)
|
||||||
for {
|
for {
|
||||||
vc = <-sc.incoming
|
vc = <-sc.incoming
|
||||||
if vc.Target.Script != sc.script {
|
if vc.Target.Script != sc.script {
|
||||||
// TODO clear this object out of the exits table
|
|
||||||
sc.script = vc.Target.Script
|
sc.script = vc.Target.Script
|
||||||
l = lua.NewState()
|
l = lua.NewState()
|
||||||
|
|
||||||
|
@ -145,16 +146,17 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage)
|
||||||
l.SetGlobal("down", lua.LString(dirBelow))
|
l.SetGlobal("down", lua.LString(dirBelow))
|
||||||
|
|
||||||
// witch object behavior functions
|
// witch object behavior functions
|
||||||
l.SetGlobal("has", l.NewFunction(witchHas))
|
l.SetGlobal("has", l.NewFunction(sc.wHas))
|
||||||
l.SetGlobal("hears", l.NewFunction(witchHears))
|
l.SetGlobal("hears", l.NewFunction(sc.wHears))
|
||||||
l.SetGlobal("sees", l.NewFunction(witchSees))
|
l.SetGlobal("sees", l.NewFunction(sc.wSees))
|
||||||
l.SetGlobal("goes", l.NewFunction(witchGoes))
|
l.SetGlobal("goes", l.NewFunction(sc.wGoes))
|
||||||
l.SetGlobal("seen", l.NewFunction(witchSeen))
|
l.SetGlobal("seen", l.NewFunction(sc.wSeen))
|
||||||
l.SetGlobal("my", l.NewFunction(witchMy))
|
l.SetGlobal("my", l.NewFunction(sc.wMy))
|
||||||
l.SetGlobal("provides", l.NewFunction(witchProvides))
|
l.SetGlobal("provides", l.NewFunction(sc.wProvides))
|
||||||
|
|
||||||
// witch helpers
|
// witch helpers
|
||||||
l.SetGlobal("_handlers", l.NewTable())
|
l.SetGlobal("_handlers", l.NewTable())
|
||||||
|
l.SetGlobal("_ID", lua.LNumber(vc.Target.ID))
|
||||||
|
|
||||||
if err := l.DoString(vc.Target.Script); err != nil {
|
if err := l.DoString(vc.Target.Script); err != nil {
|
||||||
log.Printf("error parsing script %s: %s", vc.Target.Script, err.Error())
|
log.Printf("error parsing script %s: %s", vc.Target.Script, err.Error())
|
||||||
|
@ -187,7 +189,7 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage)
|
||||||
senderID := int(lua.LVAsNumber(sender.RawGetString("ID")))
|
senderID := int(lua.LVAsNumber(sender.RawGetString("ID")))
|
||||||
owner := l.ToString(1)
|
owner := l.ToString(1)
|
||||||
name := l.ToString(2)
|
name := l.ToString(2)
|
||||||
db := sc.serverAPI.DB()
|
db := sc.db
|
||||||
senderObj, err := db.GetObjectByID(senderID)
|
senderObj, err := db.GetObjectByID(senderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println(err.Error())
|
log.Println(err.Error())
|
||||||
|
@ -224,6 +226,7 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage)
|
||||||
senderT.RawSetString("ID", lua.LNumber(vc.Sender.ID))
|
senderT.RawSetString("ID", lua.LNumber(vc.Sender.ID))
|
||||||
l.SetGlobal("sender", senderT)
|
l.SetGlobal("sender", senderT)
|
||||||
l.SetGlobal("msg", lua.LString(vc.Rest))
|
l.SetGlobal("msg", lua.LString(vc.Rest))
|
||||||
|
l.SetGlobal("_SENDERID", lua.LNumber(vc.Sender.ID))
|
||||||
|
|
||||||
handlers := l.GetGlobal("_handlers").(*lua.LTable)
|
handlers := l.GetGlobal("_handlers").(*lua.LTable)
|
||||||
handlers.ForEach(func(k, v lua.LValue) {
|
handlers.ForEach(func(k, v lua.LValue) {
|
||||||
|
@ -254,3 +257,126 @@ func NewScriptContext(db db.DB, getSend func(string) func(*proto.ClientMessage)
|
||||||
func (sc *ScriptContext) Handle(vc VerbContext) {
|
func (sc *ScriptContext) Handle(vc VerbContext) {
|
||||||
sc.incoming <- vc
|
sc.incoming <- vc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) addHandler(l *lua.LState, verb, pattern string, cb *lua.LFunction) {
|
||||||
|
log.Printf("adding handler: %s %s %#v", verb, string(pattern), cb)
|
||||||
|
|
||||||
|
handlers := l.GetGlobal("_handlers").(*lua.LTable)
|
||||||
|
|
||||||
|
verbHandlers, ok := handlers.RawGetString(verb).(*lua.LTable)
|
||||||
|
if !ok {
|
||||||
|
verbHandlers = l.NewTable()
|
||||||
|
handlers.RawSetString(verb, verbHandlers)
|
||||||
|
}
|
||||||
|
|
||||||
|
verbHandlers.RawSetString(pattern, cb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wMy(l *lua.LState) int {
|
||||||
|
hasT := l.GetGlobal("_has").(*lua.LTable)
|
||||||
|
val := hasT.RawGetString(l.ToString(1))
|
||||||
|
l.Push(val)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wHas(l *lua.LState) int {
|
||||||
|
l.SetGlobal("_has", l.ToTable(1))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wHears(l *lua.LState) int {
|
||||||
|
pattern := l.ToString(1)
|
||||||
|
cb := l.ToFunction(2)
|
||||||
|
sc.addHandler(l, "say", pattern, cb)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wSees(l *lua.LState) int {
|
||||||
|
pattern := l.ToString(1)
|
||||||
|
cb := l.ToFunction(2)
|
||||||
|
|
||||||
|
sc.addHandler(l, "emote", pattern, cb)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wSeen(l *lua.LState) int {
|
||||||
|
cb := l.ToFunction(1)
|
||||||
|
sc.addHandler(l, "look", ".*", cb)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wDoes(ls *lua.LState) int {
|
||||||
|
// TODO how to feed events back into the server?
|
||||||
|
// it needs to behave like an event showing up in Commands stream
|
||||||
|
// this handler needs a reference to the gateway which has a channel for sending events that the server will see?
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wProvides(l *lua.LState) int {
|
||||||
|
// TODO test this manually
|
||||||
|
|
||||||
|
verbAndPattern := l.ToString(1)
|
||||||
|
cb := l.ToFunction(2)
|
||||||
|
|
||||||
|
split := strings.SplitN(verbAndPattern, " ", 2)
|
||||||
|
verb := split[0]
|
||||||
|
pattern := split[1]
|
||||||
|
|
||||||
|
sc.addHandler(l, verb, pattern, cb)
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) wGoes(l *lua.LState) int {
|
||||||
|
direction := NewDirection(l.ToString(1))
|
||||||
|
targetRoomTerm := l.ToString(2)
|
||||||
|
|
||||||
|
log.Printf("GOT DIRECTION %v", direction)
|
||||||
|
|
||||||
|
cb := func(l *lua.LState) (ret int) {
|
||||||
|
targetRoomList, err := sc.db.SearchObjectsByName(targetRoomTerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to search for target room: %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch len(targetRoomList) {
|
||||||
|
case 0:
|
||||||
|
log.Printf("failed to find any matching target room. tell player somehow")
|
||||||
|
return
|
||||||
|
case 1:
|
||||||
|
log.Printf("found the target room")
|
||||||
|
default:
|
||||||
|
log.Printf("found too many matching target rooms. tell player somehow")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
targetRoom := targetRoomList[0]
|
||||||
|
msg := l.GetGlobal("msg").String()
|
||||||
|
normalized, err := NormalizeDirection(msg)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sender, err := sc.getSenderFromState(l)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to find sender %s", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if normalized.Equals(direction) {
|
||||||
|
log.Printf("MOVING SENDER TO '%s'", targetRoom.Data["name"])
|
||||||
|
// TODO error checking
|
||||||
|
sc.db.MoveInto(*sender, targetRoom)
|
||||||
|
sc.serverAPI.Tell(targetRoom.ID, sender.ID, fmt.Sprintf("you are now in %s", targetRoom.Data["name"]))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.addHandler(l, "go", ".*", l.NewFunction(cb))
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (sc *ScriptContext) getSenderFromState(l *lua.LState) (*db.Object, error) {
|
||||||
|
lsID := lua.LVAsNumber(l.GetGlobal("_SENDERID"))
|
||||||
|
|
||||||
|
return sc.db.GetObjectByID(int(lsID))
|
||||||
|
}
|
||||||
|
|
|
@ -173,21 +173,4 @@ allows({
|
||||||
execute = "world",
|
execute = "world",
|
||||||
})
|
})
|
||||||
|
|
||||||
-- option 1: fully manual
|
goes("east", "gallery")
|
||||||
|
|
||||||
provides("go east", function(args)
|
|
||||||
if sender.where = "gallery" then
|
|
||||||
move_sender("ossuary")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
provides("go west", function(args)
|
|
||||||
if sender.where = "ossuary" then
|
|
||||||
move_sender("gallery")
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
-- option 2: magical helper
|
|
||||||
|
|
||||||
-- automatically creates the two `go` handlers above
|
|
||||||
goes("east", "gallery", "ossuary")
|
|
||||||
|
|
Loading…
Reference in New Issue