123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122 |
- package funmow
-
- import (
- "fmt"
- "regexp"
- "strings"
- "unicode"
- )
-
- const (
- MatchContext = 1 << iota
- MatchGlobalDBRef = 1 << iota
- MatchGlobalPlayer = 1 << iota
- MatchInventory = 1 << iota
- MatchRelative = 1 << iota
- MatchExitAliases = 1 << iota
- MatchExitType = 1 << iota
- MatchRoomType = 1 << iota
- MatchPlayerType = 1 << iota
- MatchThingType = 1 << iota
- MatchAnyType = MatchExitType | MatchRoomType | MatchPlayerType | MatchThingType
- MatchStuffTypes = MatchExitType | MatchRoomType | MatchThingType
- )
-
- type ExecutionContext struct {
- actor Object
- context Object
- inbound chan PlayerEvent
- outbound chan PlayerEvent
- eventDistributor *EventDistributor
- db *DB
- factory *ObjectFactory
- forceContext bool
- }
-
- func NewForceContext(e *EventDistributor, w *DB, outbound chan PlayerEvent) *ExecutionContext {
-
- c := new(ExecutionContext)
-
- c.outbound = outbound
- c.eventDistributor = e
- c.db = w
- c.factory = NewObjectFactory(w)
- c.forceContext = true
- return c
- }
-
- func NewExecutionContext(actorID DBRef, e *EventDistributor, w *DB, outbound chan PlayerEvent) *ExecutionContext {
-
- c := new(ExecutionContext)
-
- actor, found := w.Fetch(actorID)
- if !found {
- return nil
- }
-
- c.actor = actor
- c.outbound = outbound
- c.eventDistributor = e
- c.db = w
- c.factory = NewObjectFactory(w)
-
- return c
- }
-
- func (c *ExecutionContext) StartInboundChannel() chan PlayerEvent {
- c.inbound = make(chan PlayerEvent)
- inboundBuffer := make(chan PlayerEvent)
-
- go func() {
-
- // An inbound event buffer to protect the event distributor from long
- // running tasks. The alternative is to run each inbound event in a
- // separate goroutine but that has potential problems (ie, two emits
- // arrive in order; the first one requires an extra DB lookup to sort
- // out context. Now the second one ends up sending its output event
- // before the first, and the client sees things backwards.
-
- queue := make([]*PlayerEvent, 0)
- running := true
- for running {
- if len(queue) == 0 {
- select {
- case newEvent, ok := <-c.inbound:
- if !ok {
- running = false
- break
- }
- queue = append(queue, &newEvent)
- }
- } else {
- event := queue[0]
- select {
- case newEvent, ok := <-c.inbound:
- if !ok {
- running = false
- break
- }
- queue = append(queue, &newEvent)
- case inboundBuffer <- *event:
- queue = queue[1:]
- }
- }
- }
- // closure of c.inbound is the signal from the event distributor that we need to die.
- // we then close inboundBuffer to tell the event goroutine to die
- close(inboundBuffer)
- }()
-
- go func() {
- for {
- event, ok := <-inboundBuffer
- if !ok {
- break
- }
- c.HandleEvent(event)
- }
- // mark player as offline
- if c.actor.Type == "player" {
- c.actor.SetFlag("online", false)
- c.actor.Commit()
- }
- // and finally we tell the event distributor to delete us.
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeTeardownComplete}
- }()
-
- return c.inbound
- }
-
- func (c *ExecutionContext) HandleEvent(m PlayerEvent) {
-
- if m.messageType == EventTypeForce {
- found := false
- c.actor, found = c.db.Fetch(m.dst)
- contextID, found := c.db.GetParent(c.actor.ID)
- if found {
- c.context, _ = c.db.Fetch(contextID)
- } else {
- c.context, _ = c.db.Fetch(0)
- }
- if !found {
- return
- }
- c.evaluateCommand(m)
- return
- }
-
- c.actor.Refresh()
- contextID, found := c.db.GetParent(c.actor.ID)
- if found {
- c.context, _ = c.db.Fetch(contextID)
- } else {
- c.context, _ = c.db.Fetch(0)
- }
-
- switch m.messageType {
- case EventTypeLogin:
- if c.actor.Type == "player" {
- c.actor.SetFlag("online", true)
- c.actor.Commit()
- c.system("Yay! %s has connected! Oh boy!", c.actor.ColorName())
- c.oemit(c.context.ID, "You hear a rustling as %s awakens from a slumber.", c.actor.ColorName())
- }
- case EventTypeEmit:
- fallthrough
- case EventTypeOEmit:
- if m.dst == c.context.ID {
- c.output("%s", m.message)
- }
- case EventTypePEmit:
- c.output("%s", m.message)
- case EventTypeWall:
- speaker, found := c.db.Fetch(m.src)
- if !found {
- break
- }
- c.output("In the distance, you hear %s bellow out: \"%s\"", speaker.ColorName(), m.message)
- case EventTypeSystem:
- c.output(m.message)
- case EventTypePage:
- speaker, found := c.db.Fetch(m.src)
- if !found {
- break
- }
- c.output("%s pages: %s", speaker.ColorName(), m.message)
- case EventTypeSay:
- if m.dst == c.context.ID {
- speaker, found := c.db.Fetch(m.src)
- if !found {
- break
- }
- c.output("%s says \"%s\"", speaker.ColorName(), m.message)
- }
- case EventTypePose:
- if m.dst == c.context.ID {
- if m.src == c.actor.ID {
- c.output("%s %s", c.actor.ColorName(), m.message)
- } else {
- speaker, found := c.db.Fetch(m.src)
- if !found {
- break
- }
- c.output("%s %s", speaker.ColorName(), m.message)
- }
- }
- case EventTypeCommand:
- c.evaluateCommand(m)
- }
- }
-
- func (c *ExecutionContext) evaluateCommand(m PlayerEvent) {
- command := m.message
- switch {
- case command == "whoami":
- c.output(c.actor.Name)
- case command == "l":
- c.lookCmd("")
- case command == "look":
- c.lookCmd("")
- case strings.HasPrefix(command, "l "): // look at
- c.lookCmd(strings.TrimPrefix(command, "l "))
- case strings.HasPrefix(command, "look "): // look at
- c.lookCmd(strings.TrimPrefix(command, "look "))
- case strings.HasPrefix(command, "ex "):
- c.examineCmd(strings.TrimPrefix(command, "ex "))
- case strings.HasPrefix(command, "examine "):
- c.examineCmd(strings.TrimPrefix(command, "examine "))
- case strings.HasPrefix(command, "\""):
- c.sayCmd(strings.TrimPrefix(command, "\""))
- case strings.HasPrefix(command, "say "):
- c.sayCmd(strings.TrimPrefix(command, "say "))
- case strings.HasPrefix(command, ":"):
- c.poseCmd(strings.TrimPrefix(command, ":"))
- case strings.HasPrefix(command, "pose "):
- c.poseCmd(strings.TrimPrefix(command, "pose "))
- case strings.HasPrefix(command, "p "):
- c.pageCmd(command)
- case strings.HasPrefix(command, "page "):
- c.pageCmd(command)
- case command == "i":
- c.inventoryCmd()
- case command == "inventory":
- c.inventoryCmd()
- case strings.HasPrefix(command, "get "):
- c.getCmd(strings.TrimPrefix(command, "get "))
- case strings.HasPrefix(command, "drop "):
- c.dropCmd(strings.TrimPrefix(command, "drop "))
- case strings.HasPrefix(command, "give "):
- c.giveCmd(command)
- case strings.HasPrefix(command, "put "):
- c.putCmd(command)
- case strings.HasPrefix(command, "enter "):
- c.enterCmd(strings.TrimPrefix(command, "enter "))
- case command == "leave":
- c.leaveCmd()
- case command == "quit":
- c.quitCmd(m.connectionID)
- case command == "WHO":
- c.whoCmd()
- case strings.HasPrefix(command, "@create "):
- c.createCmd(strings.TrimPrefix(command, "@create "))
- case strings.HasPrefix(command, "@dig "):
- c.digCmd(command)
- case strings.HasPrefix(command, "@open "):
- c.openCmd(command)
- case strings.HasPrefix(command, "@name "):
- c.nameCmd(command)
- case strings.HasPrefix(command, "@desc "):
- c.descCmd(command)
- case strings.HasPrefix(command, "@password "):
- c.passwordCmd(command)
- case strings.HasPrefix(command, "@set "):
- c.setCmd(command)
- case strings.HasPrefix(command, "@color "):
- c.colorCmd(command)
- case strings.HasPrefix(command, "@tel "):
- c.telCmd(strings.TrimPrefix(command, "@tel "))
- case strings.HasPrefix(command, "@dump "):
- c.dumpCmd(strings.TrimPrefix(command, "@dump "))
- case strings.HasPrefix(command, "@destroy "):
- c.destroyCmd(strings.TrimPrefix(command, "@destroy "))
- case strings.HasPrefix(command, "@force "):
- c.forceCmd(command)
-
- default:
- if !c.goCmd(command) {
- c.output("What?\n")
- }
- }
-
- }
-
- func (c *ExecutionContext) lookCmd(target string) {
-
- if len(target) > 0 {
- object, found := c.MatchFirst(c.context.ID, target, MatchContext|MatchInventory|MatchRelative|MatchAnyType|MatchExitAliases)
- if !found {
- c.output("I don't see that here.")
- return
- }
- c.output("%s\n%s", object.DetailedName(), object.Description)
- } else {
- c.output("%s\n%s", c.context.DetailedName(), c.context.Description)
- contents := c.context.GetContents(c.actor.ID, false)
- if len(contents) > 0 {
- c.output("Contents:\n" + strings.Join(contents, "\n"))
- }
- exits := c.context.GetExits(true, false)
- if len(exits) > 0 {
- c.output("Obvious Exits:\n" + strings.Join(exits, " "))
- }
- }
-
- }
-
- func (c *ExecutionContext) objectName(id DBRef) string {
- o, found := c.db.Fetch(id)
- if found {
- return o.DetailedName()
- } else {
- return fmt.Sprintf("MISSING OBJECT <#%d>", id)
- }
- }
-
- func (c *ExecutionContext) examineCmd(objectName string) {
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchInventory|MatchRelative|MatchAnyType|MatchExitAliases|MatchGlobalDBRef)
- if !found {
- c.output("I don't see that here.")
- return
- }
-
- containerID, _ := c.db.GetParent(object.ID)
-
- c.output("%s", object.DetailedName())
- c.output("Type: %s", object.Type)
- c.output("@name: %s", object.Name)
- c.output("@desc: %s", object.Description)
- c.output("Next: %s", c.objectName(object.Next))
- c.output("Owner: %s", c.objectName(object.Owner))
- c.output("Location: %s", c.objectName(containerID))
-
- contents := object.GetContents(0, true)
- if len(contents) > 0 {
- c.output("Contains:\n%s", strings.Join(contents, "\n"))
- }
-
- exits := object.GetExits(false, true)
- if len(exits) > 0 {
- c.output("Exits:\n%s", strings.Join(exits, "\n"))
- }
-
- flags := make([]string, 0, len(object.Flags))
- for k, v := range object.Flags {
- if v {
- flags = append(flags, k)
- }
- }
- c.output("Flags: %s", strings.Join(flags, ", "))
-
- properties := make([]string, 0, len(object.Properties))
- for k, v := range object.Properties {
- properties = append(properties, fmt.Sprintf("@%s: %s", k, v))
- }
- c.output("Properties:\n%s", strings.Join(properties, "\n"))
-
- }
-
- func (c *ExecutionContext) forceCmd(input string) {
-
- r, _ := regexp.Compile(`^@force\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- objectName, command := params[1], params[2]
-
- wizard := c.actor.GetFlag("wizard")
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchGlobalDBRef|MatchExitAliases|MatchInventory|MatchRelative|MatchStuffTypes)
- if !found {
- c.output("I don't see that here.")
- return
- }
- if object.Owner != c.actor.ID && !wizard {
- c.output("It's not nice to touch other people's things.")
- return
- }
-
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: object.ID, message: command, messageType: EventTypeForce}
-
- }
-
- func (c *ExecutionContext) sayCmd(message string) {
-
- c.output(`You say "%s"`, message)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.context.ID, message: message, messageType: EventTypeSay}
-
- }
-
- func (c *ExecutionContext) poseCmd(message string) {
-
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.context.ID, message: message, messageType: EventTypePose}
-
- }
-
- func (c *ExecutionContext) pageCmd(input string) {
-
- r, _ := regexp.Compile(`^p(?:age)*\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*[^\pZ]+)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- searchName, message := params[1], params[2]
-
- candidate, found := c.MatchPlayerName(searchName)
- if !found {
- c.output("I don't know who you're trying to page.")
- return
- }
- if !candidate.GetFlag("online") {
- c.output("That player appears to be offline.")
- return
- }
-
- c.output(`You paged %s with "%s".`, candidate.ColorName(), message)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: candidate.ID, message: message, messageType: EventTypePage}
-
- }
-
- func (c *ExecutionContext) inventoryCmd() {
-
- inventory := c.actor.GetContents(0, true)
-
- if len(inventory) > 0 {
- c.output("Inventory:\n %s", strings.Join(inventory, "\n "))
- } else {
- c.output("You're not carrying anything.")
- }
-
- }
-
- func (c *ExecutionContext) getCmd(objectName string) {
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchGlobalDBRef|MatchAnyType)
- if !found {
- c.output("I don't see that here.")
- return
- }
- if object.Type == "exit" {
- c.output("You can't pick pick up exits.")
- return
- }
- if object.Type == "player" {
- c.output("That's really annoying. Don't be that person.")
- return
- }
- if object.ID == c.actor.ID {
- c.output("You can't pick yourself up.")
- return
- }
-
- err := c.actor.Contains(&object)
- if err != nil {
- return
- }
- //c.actor.Refresh()
- c.output("You pick up %s.", object.ColorName())
- c.pemit(object.ID, "%s picked you up.", c.actor.ColorName())
- c.oemit(c.context.ID, "%s picks up %s.", c.actor.ColorName(), object.ColorName())
-
- }
-
- func (c *ExecutionContext) putCmd(input string) {
- c.xferCmd(input, "put", "into")
- }
-
- func (c *ExecutionContext) giveCmd(input string) {
- c.xferCmd(input, "give", "to")
- }
-
- func (c *ExecutionContext) xferCmd(input string, verb string, preposition string) {
-
- r, _ := regexp.Compile(`^` + verb + `\pZ+([^=]*[^=\pZ]{1})\pZ*` + preposition + `\pZ*(.*)\pZ*$`)
-
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- objectName, receiverName := params[1], params[2]
-
- object, found := c.MatchFirst(c.actor.ID, objectName, MatchInventory|MatchThingType)
- if !found {
- c.output("You can't " + verb + " what you don't have.")
- return
- }
- receiver, found := c.MatchFirst(c.context.ID, receiverName, MatchContext|MatchThingType|MatchPlayerType)
- if !found {
- c.output("I cant find who or what you want to " + verb + " this " + preposition + ".")
- return
- }
-
- err := receiver.Contains(&object)
- if err != nil {
- return
- }
-
- c.output("You "+verb+" %s "+preposition+" %s.", object.ColorName(), receiver.ColorName())
- c.pemit(object.ID, "%s "+verb+"s you "+preposition+" %s.", c.actor.ColorName(), receiver.ColorName())
-
- if verb == "give" {
- c.pemit(receiver.ID, "%s gives you %s.", c.actor.ColorName(), object.ColorName())
- } else {
- c.pemit(receiver.ID, "%s puts %s into you.", c.actor.ColorName(), object.ColorName())
- }
-
- }
-
- func (c *ExecutionContext) MatchPlayerName(matchName string) (Object, bool) {
- playerMeta, foundMeta := c.db.GetPlayer(matchName)
- if foundMeta {
- o, found := c.db.Fetch(playerMeta.ID)
- if found {
- return o, true
- }
- }
- return Object{}, false
- }
-
- func (c *ExecutionContext) MatchFirst(context DBRef, matchName string, matchType int) (Object, bool) {
-
- wanted := map[string]bool{
- "player": matchType&MatchPlayerType != 0,
- "exit": matchType&MatchExitType != 0,
- "room": matchType&MatchRoomType != 0,
- "thing": matchType&MatchThingType != 0,
- }
-
- if matchType&MatchRelative != 0 {
- if matchName == "here" {
- o, found := c.db.Fetch(context)
- if found && wanted[o.Type] {
- return o, true
- }
- }
-
- if matchName == "me" {
- if wanted[c.actor.Type] {
- return c.actor, true
- }
- }
- }
-
- ref, valid := NewDBRefFromHashRef(matchName)
-
- if valid {
- o, found := c.db.Fetch(ref)
- if found && wanted[o.Type] {
- container, _ := c.db.GetParent(o.ID)
- if container == context && matchType&MatchContext != 0 {
- return o, true
- }
- if container == c.actor.ID && matchType&MatchInventory != 0 {
- return o, true
- }
- if matchType&MatchGlobalDBRef != 0 {
- return o, true
- }
- }
- }
-
- if wanted["player"] && matchType&MatchGlobalPlayer != 0 {
- o, found := c.MatchPlayerName(matchName)
- if found {
- return o, true
- }
- }
-
- if matchType&MatchContext != 0 {
- for childID, _ := range c.db.GetChildren(context) {
- o, found := c.db.Fetch(childID)
- if found && wanted[o.Type] {
- if o.Type == "exit" && matchType&MatchExitAliases != 0 {
- aliases := strings.Split(o.Name, ";")
- for _, v := range aliases {
- if strings.EqualFold(v, matchName) {
- return o, true
- }
- }
- }
- lowerObjectName := strings.ToLower(o.Name)
- lowerMatchName := strings.ToLower(matchName)
- if strings.HasPrefix(lowerObjectName, lowerMatchName) {
- return o, true
- }
- }
- }
- }
-
- if matchType&MatchInventory != 0 {
- for childID, _ := range c.db.GetChildren(c.actor.ID) {
- o, found := c.db.Fetch(childID)
- if found && wanted[o.Type] {
- lowerObjectName := strings.ToLower(o.Name)
- lowerMatchName := strings.ToLower(matchName)
- if strings.HasPrefix(lowerObjectName, lowerMatchName) {
- return o, true
- }
- }
- }
- }
-
- return Object{}, false
-
- }
-
- func (c *ExecutionContext) dropCmd(objectName string) {
-
- object, found := c.MatchFirst(c.actor.ID, objectName, MatchInventory|MatchAnyType)
- if !found {
- c.output("You're not carrying that.")
- return
- }
-
- err := c.context.Contains(&object)
- if err != nil {
- return
- }
-
- c.output("You drop %s.", object.ColorName())
- c.pemit(object.ID, "%s drops you.", c.actor.ColorName())
- c.oemit(c.context.ID, "%s drops %s.", c.actor.ColorName(), object.ColorName())
-
- }
-
- func (c *ExecutionContext) enterCmd(objectName string) {
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchThingType)
- if !found {
- c.output("I don't see that here.")
- return
- }
-
- if object.Type == "player" {
- c.output("Maybe you should seek consent prior to entering another player.")
- return
- }
- if object.Type == "exit" {
- c.output("This s not how exits are meant to be used.")
- return
- }
- if object.ID == c.actor.ID {
- c.output("Entering yourself would be a bad idea.")
- return
- }
-
- if !object.GetFlag("enter_ok") && !c.actor.GetFlag("wizard") {
- c.output("You're not allowed to do that.")
- return
- }
-
- err := object.Contains(&c.actor)
- if err != nil {
- return
- }
- c.output("You climb into %s.", object.ColorName())
- c.oemit(c.context.ID, "%s climbs into %s.", c.actor.ColorName(), object.ColorName())
- c.oemit(object.ID, "%s squeezes into %s with you.", c.actor.ColorName(), object.ColorName())
-
- }
-
- func (c *ExecutionContext) leaveCmd() {
-
- outerObjectID, _ := c.db.GetParent(c.context.ID)
- if outerObjectID == 0 { // probably trying to 'leave' a room
- c.output("You can't leave here.")
- return
- }
-
- container, found := c.db.Fetch(outerObjectID)
- if !found {
- return
- }
-
- err := container.Contains(&c.actor)
- if err != nil {
- return
- }
-
- c.output("You climb out of %s.", c.context.ColorName())
- c.oemit(c.context.ID, "%s climbs out of %s.", c.actor.ColorName(), c.context.ColorName())
- c.oemit(container.ID, "%s climbs out of %s.", c.actor.ColorName(), c.context.ColorName())
-
- }
-
- func (c *ExecutionContext) quitCmd(connectionID int) {
-
- c.output("So long, it's been good to know yah.")
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, messageType: EventTypeQuit, connectionID: connectionID}
-
- }
-
- func (c *ExecutionContext) whoCmd() {
- onlinePlayers := c.eventDistributor.OnlinePlayers()
-
- c.output("Currently Online:")
-
- for _, ref := range onlinePlayers {
- c.output("%s", c.objectName(ref))
- }
- }
-
- func (c *ExecutionContext) createCmd(message string) {
-
- o := c.factory.NewThing()
- o.Name = strings.TrimSpace(message)
- o.Owner = c.actor.ID
- o.Commit()
-
- err := c.actor.Contains(&o)
- if err != nil {
- return
- }
-
- c.output("%s Created.", o.DetailedName())
-
- }
-
- func (c *ExecutionContext) openCmd(input string) {
- // @open <in1;in2;in3;etc>=#<room>,<out1;out2;out3;etc>
-
- r, _ := regexp.Compile(`^@open\pZ+([^=]*[^=\pZ]{1})\pZ*=#([0-9]+)(?:\pZ*,\pZ*([^,]*[^,\pZ]{1})\pZ*)?`)
- params := r.FindStringSubmatch(input)
-
- if params == nil {
- return
- }
-
- inExit, roomIDStr, outExit := params[1], params[2], params[3]
-
- if len(inExit) == 0 || len(roomIDStr) == 0 {
- c.output("Bad command or file name.")
- return
- }
-
- targetID, _ := NewDBRefFromString(roomIDStr) // this will never fail, the regexp guarantees that
- targetRoom, found := c.db.Fetch(targetID)
- if !found {
- c.output("Target not found.")
- return
- }
-
- toExit := c.factory.NewExit(inExit, targetRoom.ID, c.actor.ID)
- toExit.Commit()
- err := c.context.Contains(&toExit)
- if err != nil {
- return
- }
- c.output("%s Created.", toExit.DetailedName())
-
- if len(outExit) > 0 {
- fromExit := c.factory.NewExit(outExit, c.context.ID, c.actor.ID)
- fromExit.Commit()
- err = targetRoom.Contains(&fromExit)
- if err != nil {
- return
- }
- c.output("%s Created.", fromExit.DetailedName())
- }
-
- }
-
- func (c *ExecutionContext) digCmd(input string) {
- // @dig <Room name>=<in1;in2;in3;etc>,<out1;out2;out3;etc>
- //@dig foo bar = <F>oo;foo;f,<B>ack;back;b
-
- r, _ := regexp.Compile(`^@dig\pZ+([^=]*[^=\pZ]{1})(?:\pZ*=\pZ*(?:([^,]*[^,\pZ]{1})\pZ*)?(?:\pZ*,\pZ*([^,]*[^,\pZ]{1})\pZ*)?)?`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- roomName, inExit, outExit := params[1], params[2], params[3]
-
- if len(roomName) == 0 {
- c.output("Rooms can't not have names.")
- return
- }
-
- newRoom := c.factory.NewRoom()
- newRoom.Name = roomName
- newRoom.Owner = c.actor.ID
- newRoom.Commit()
-
- c.output("%s Created.", newRoom.DetailedName())
-
- if len(inExit) > 0 || len(outExit) > 0 {
- if len(inExit) > 0 {
- toExit := c.factory.NewExit(inExit, newRoom.ID, c.actor.ID)
- toExit.Commit()
- err := c.context.Contains(&toExit)
- if err != nil {
- return
- }
- c.output("%s Created.", toExit.DetailedName())
- }
- if len(outExit) > 0 {
- fromExit := c.factory.NewExit(outExit, c.context.ID, c.actor.ID)
- fromExit.Commit()
- err := newRoom.Contains(&fromExit)
- if err != nil {
- return
- }
- c.output("%s Created.", fromExit.DetailedName())
- }
- }
-
- }
-
- func (c *ExecutionContext) passwordCmd(input string) {
-
- if c.actor.Type != "player" {
- c.output("Only players can have passwords.")
- return
- }
-
- r, _ := regexp.Compile(`^@password\pZ+([^\pZ]+)\pZ*=\pZ*([^\pZ]+)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- oldPassword, newPassword := params[1], params[2]
-
- if len(oldPassword) == 0 || len(newPassword) == 0 {
- c.output("Password can't be blank.")
- return
- }
-
- changed := c.db.SetPlayerPassword(c.actor.Name, oldPassword, newPassword)
- if changed {
- c.output("Password updated.")
- } else {
- c.output("Old password is wrong.")
- }
-
- }
-
- func (c *ExecutionContext) nameCmd(input string) {
-
- r, _ := regexp.Compile(`^@name\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- searchName, newName := params[1], params[2]
-
- candidate, found := c.MatchFirst(c.context.ID, searchName, MatchContext|MatchInventory|MatchRelative|MatchGlobalDBRef|MatchExitAliases|MatchAnyType)
-
- if !found {
- c.output("I don't see that here.")
- return
- }
-
- if candidate.Type == "player" {
- i := strings.IndexFunc(newName, func(c rune) bool {
- return unicode.IsSpace(c)
- })
- if i != -1 {
- c.output("Player names can't have spaces.")
- return
- }
- if c.actor.ID != candidate.ID && !c.actor.GetFlag("wizard") {
- c.output("Only wizards can rename other players.")
- return
- }
- err := c.db.RenamePlayer(candidate.Name, newName)
- if err != nil {
- c.output("I can't do that. Something has gone wrong.")
- return
- }
- }
- candidate.Name = newName
- candidate.Commit()
- c.output("Name set.")
-
- }
-
- func (c *ExecutionContext) descCmd(input string) {
-
- r, _ := regexp.Compile(`^@desc\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(.*)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- objectName, description := params[1], params[2]
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchInventory|MatchRelative|MatchGlobalDBRef|MatchExitAliases|MatchAnyType)
- if !found {
- c.output("I don't see that here.")
- return
- }
-
- object.Description = description
- object.Commit()
-
- c.output("Description set.")
-
- }
-
- func (c *ExecutionContext) setCmd(input string) {
- r, _ := regexp.Compile(`^@set\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*(!)?(.*)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- objectName, value, flag := params[1], params[2] != "!", params[3]
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchInventory|MatchRelative|MatchGlobalDBRef|MatchExitAliases|MatchAnyType)
- if !found {
- c.output("I don't know what that is")
- return
- }
-
- if object.Owner != c.actor.ID && !c.actor.GetFlag("wizard") {
- c.output("You're not allowed to do that.")
- return
- }
-
- object.SetFlag(flag, value)
- object.Commit()
-
- c.output("It is so.")
-
- }
-
- func (c *ExecutionContext) colorCmd(input string) {
-
- r, _ := regexp.Compile(`^@color\pZ+([^=]*[^=\pZ]{1})\pZ*=\pZ*([^\pZ]*)\pZ*$`)
- params := r.FindStringSubmatch(input)
- if params == nil {
- return
- }
-
- objectName, value := params[1], params[2]
-
- object, found := c.MatchFirst(c.context.ID, objectName, MatchContext|MatchInventory|MatchRelative|MatchGlobalDBRef|MatchExitAliases|MatchAnyType)
-
- if !found {
- c.output("I don't know what that is")
- return
- }
-
- if object.Owner != c.actor.ID && !c.actor.GetFlag("wizard") {
- c.output("You're not allowed to do that.")
- return
- }
-
- object.SetProp("color", value)
- object.Commit()
-
- c.output("It is so.")
-
- }
-
- func (c *ExecutionContext) telCmd(destStr string) {
-
- var dest Object
- var found bool
-
- dest, found = c.MatchFirst(c.context.ID, destStr, MatchGlobalDBRef|MatchRoomType)
-
- if !found {
- c.output("Invalid destination.")
- return
- }
-
- if dest.Owner != c.actor.ID && !dest.GetFlag("jump_ok") && !c.actor.GetFlag("wizard") {
- c.output("You're not allowed to do that.")
- return
- }
-
- c.output("You feel an intense wooshing sensation.")
- c.oemit(c.context.ID, "%s teleports out of the room.", c.actor.ColorName())
- c.oemit(dest.ID, "%s teleports in to the room.", c.actor.ColorName())
-
- err := dest.Contains(&c.actor)
- if err != nil {
- return
- }
-
- c.command("look")
-
- }
-
- func (c *ExecutionContext) dumpCmd(input string) {
-
- object, found := c.MatchFirst(c.context.ID, input, MatchContext|MatchInventory|MatchRelative|MatchGlobalDBRef|MatchGlobalPlayer|MatchExitAliases|MatchAnyType)
-
- if !found {
- c.output("I can't find that.")
- return
- }
-
- c.output("%s", c.db.DumpObject(object.ID))
-
- }
-
- func (c *ExecutionContext) destroyCmd(target string) {
-
- object, found := c.MatchFirst(c.context.ID, target, MatchContext|MatchGlobalDBRef|MatchRelative|MatchExitAliases|MatchInventory|MatchStuffTypes)
- if !found {
- c.output("I don't see that here.")
- return
- }
-
- if object.ID == c.actor.ID {
- c.output("There are alternatives to suicide.")
- return
- }
- if object.Type == "player" {
- c.output("I didn't think homicide was your thing.")
- return
- }
-
- if object.Owner != c.actor.ID && !c.actor.GetFlag("wizard") {
- c.output("You're not allowed to do that.")
- return
- }
-
- name := object.DetailedName()
- err := object.Delete()
- if err == nil {
- c.output("%s vanishes into thin air.", name)
- }
-
- }
-
- func (c *ExecutionContext) goCmd(dir string) bool {
-
- exit, found := c.MatchFirst(c.context.ID, dir, MatchContext|MatchExitType|MatchExitAliases)
-
- if !found {
- return false
- }
-
- if !exit.Next.Valid() {
- return false
- }
-
- newRoom, found := c.db.Fetch(exit.Next)
- if !found {
- c.output("That exit appears to be broken!")
- return true
- }
- err := newRoom.Contains(&c.actor)
- if err != nil {
- return false
- }
- //c.actor.Refresh()
- c.output("You head towards %s.", newRoom.DetailedName())
- c.oemit(c.context.ID, "%s leaves the room.", c.actor.ColorName())
- c.oemit(newRoom.ID, "%s enters the room.", c.actor.ColorName())
- c.command("look")
- return true
- }
-
- func (c *ExecutionContext) command(format string, a ...interface{}) {
-
- command := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, message: command, messageType: EventTypeCommand}
-
- }
-
- func (c *ExecutionContext) wall(format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, message: message, messageType: EventTypeWall}
-
- }
-
- func (c *ExecutionContext) system(format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, message: message, messageType: EventTypeSystem}
-
- }
-
- func (c *ExecutionContext) oemit(audience DBRef, format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: audience, message: message, messageType: EventTypeOEmit}
-
- }
-
- func (c *ExecutionContext) output(format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- if !c.forceContext {
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: c.actor.ID, message: message, messageType: EventTypeOutput}
- }
- }
-
- func (c *ExecutionContext) pemit(target DBRef, format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: target, message: message, messageType: EventTypePEmit}
-
- }
-
- func (c *ExecutionContext) emit(audience DBRef, format string, a ...interface{}) {
-
- message := fmt.Sprintf(format, a...)
- c.outbound <- PlayerEvent{src: c.actor.ID, dst: audience, message: message, messageType: EventTypeEmit}
-
- }
|