package funmow import ( "fmt" "sort" "strings" ) const ( MatchNone = iota MatchOne MatchMany ) type PlayerMeta struct { ID DBRef `json:"id"` Password string `json:"password"` } type Object struct { ID DBRef `json:"id"` Type string `json:"type"` Owner DBRef `json:"owner"` Next DBRef `json:"next"` Name string `json:"name"` Description string `json:"description"` Flags map[string]bool `json:"flags"` Properties map[string]string `json:"properties"` db *DB } type ObjectFactory struct { db *DB } func NewObjectFactory(db *DB) *ObjectFactory { return &ObjectFactory{db: db} } func (f *ObjectFactory) NewObject() Object { o := Object{} o.ID, _ = f.db.Allocate() o.db = f.db return o } func (f *ObjectFactory) NewExit(name string, next DBRef, owner DBRef) Object { o := Object{ Type: "exit", Name: name, Next: next, Owner: owner, db: f.db, } o.ID, _ = f.db.Allocate() return o } func (f *ObjectFactory) NewRoom() Object { o := Object{} o.ID, _ = f.db.Allocate() o.Type = "room" o.db = f.db return o } func (f *ObjectFactory) NewThing() Object { o := Object{} o.ID, _ = f.db.Allocate() o.Type = "thing" o.db = f.db return o } func (o *Object) Commit() error { return o.db.StoreObject(*o, o.ID) } func (o *Object) Refresh() bool { refreshed, found := o.db.RetrieveObject(o.ID) if found { *o = refreshed } return found } func (o Object) String() string { return fmt.Sprintf("id %d: %s", o.ID, o.Name) } func (o *Object) Remove(c *Object) error { return o.db.Unlink(o.ID, c.ID) } func (o *Object) Delete() error { err := o.db.Delete(o.ID) if err == nil { *o = Object{} } return err } func (o *Object) Contains(c *Object) error { return o.db.Link(o.ID, c.ID, c.Type) } func (o *Object) MatchExitNames(name string) ObjectList { // so much copypasta r := make(ObjectList, 0) children := o.db.GetChildren(o.ID) // map[DBRef]string for childID, childType := range children { if childType != "exit" { continue } o, found := o.db.Fetch(childID) if found { idName := fmt.Sprintf("#%d", childID) if strings.EqualFold(o.Name, name) || name == idName { r = append(r, o) break // have a match. Don't need to look for any more. } aliases := strings.Split(o.Name, ";") for _, v := range aliases { if v == name { r = append(r, o) break // no need to look at other aliases } } } } return r } func (o *Object) DetailedName() string { return fmt.Sprintf("%s <#%d>", o.Name, o.ID) } func (o *Object) GetContents(exclude DBRef) []string { r := make([]string, 0) children := o.db.GetChildren(o.ID) for childID, linkType := range children { if childID == exclude { continue } if !(linkType == "player" || linkType == "thing") { continue } o, found := o.db.Fetch(childID) if !found { continue } if linkType == "player" && !o.GetFlag("online") { continue } r = append(r, o.DetailedName()) } sort.Strings(r) return r } func (o *Object) GetExits() []string { r := make([]string, 0) children := o.db.GetChildren(o.ID) for exitID, linkType := range children { if linkType != "exit" { continue } exit, found := o.db.Fetch(exitID) if !found { continue } aliases := strings.Split(exit.Name, ";") r = append(r, aliases[0]) } sort.Strings(r) return r } func (o *Object) SetFlag(flag string, value bool) { if o.Flags == nil { o.Flags = make(map[string]bool) } o.Flags[flag] = value } func (o *Object) GetFlag(flag string) bool { if o.Flags == nil { return false } value, ok := o.Flags[flag] if !ok { return false } return value } func (o *Object) SetProp(key string, value string) { if o.Properties == nil { o.Properties = make(map[string]string) } o.Properties[key] = value } func (o *Object) GetProp(key string) string { if o.Properties == nil { return "" } value, ok := o.Properties[key] if !ok { return "" } return value } type ObjectList []Object func (l ObjectList) First() Object { if len(l) > 0 { return l[0] } else { return Object{} } } func (l ObjectList) ExactlyOne() (Object, int) { c := len(l) if c == 0 { return Object{}, MatchNone } else if c == 1 { return l[0], MatchOne } else { return Object{}, MatchMany } }