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"` Next DBRef `json:"next"` Type string `json:"type"` Name string `json:"name"` Description string `json:"description"` Flags map[string]string `json:"flags"` Owner DBRef `json:"owner"` 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) MatchLinkNames(matchName string, player DBRef) ObjectList { if matchName == "here" { return ObjectList{*o} } if matchName == "me" { p, found := o.db.Fetch(player) if !found { return ObjectList{} } else { return ObjectList{p} } } r := make(ObjectList, 0) children := o.db.GetChildren(o.ID) // map[DBRef]string for childID, _ := range children { o, found := o.db.Fetch(childID) if found { idName := fmt.Sprintf("#%d", o.ID) lowerObjectName := strings.ToLower(o.Name) lowerMatchName := strings.ToLower(matchName) if strings.HasPrefix(lowerObjectName, lowerMatchName) || matchName == idName { r = append(r, o) } } } return r } 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) GetLinkNames(matchType string, exclude DBRefList) []string { r := make([]string, 0) children := o.db.GetChildren(o.ID) // map[DBRef]string childLoop: for childID, linkType := range children { if matchType != "*" && matchType != linkType { continue } for _, excludeID := range exclude { if excludeID == childID { continue childLoop } } o, found := o.db.Fetch(childID) if found { if linkType == "player" { if o.GetFlag("online","false") == "true" { r = append(r, o.DetailedName()) } } else if linkType == "exit" { r = append(r, o.Name) } else { r = append(r, o.DetailedName()) } } } sort.Strings(r) return r } func (o *Object) SetFlag(flag string, value string) { if o.Flags == nil { o.Flags = make(map[string]string) } o.Flags[flag]=value } func (o *Object) GetFlag(flag string, defaultValue string) (string) { if o.Flags == nil { return defaultValue } value, ok := o.Flags[flag] if !ok { return defaultValue } 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 } }