Up to Main Index                          Up to Journal for February, 2016

                    JOURNAL FOR FRIDAY 12TH FEBRUARY, 2016
______________________________________________________________________________

SUBJECT: Details for latest public Git dev branch update
   DATE: Fri 12 Feb 22:25:37 GMT 2016

Just pushed some updates out to the public Git dev branch. This includes
updating all of the commands to use the location Inventory stashed in the
command processing state:


  // Instead of...
  if a := attr.FindLocate(s.actor); a != nil {
    where = a.Where()
  }
  what := where.Search(name)

  // We can use...
  what := s.where.Search(name)


When processing commands we always find out where we are so we can lock the
location. It therefore makes sense to cache this information in the state as
most commands can make use of it.

Another convenience / cleanup is the addition of the s.msg.observer message
buffer. s.msg.observer is now aliased to s.msg.observers[s.where] - they both
point to the same message buffer. This means, for the common case, sending
messages to the actor, participant and observers is consistent:


  s.msg.actor.WriteString("You wave at Bob.")
  s.msg.participant.WriteString("Diddymus waves to you.")
  s.msg.observer.WriteString("Diddymus waves to Bob.")


The only time you have to use s.msg.observers[where] is when you want to
notify observers in a location other than to the actor's current location.
Another silly example just to illustrate:


  to := exits.LeadsTo("south")
  s.msg.actor.WriteString("You roll a barrel through the south door.")
  s.msg.observer.WriteString("Diddymus rolls a barrel through the south door.")
  s.msg.observers[to].WriteString("A barrel rolls in through the north door.")


For a real working example of multiple locations see the source for the MOVE
command: cmd/move.go

The command processing state has a new silent method. Its signature is:


  func (s *state) silent(actor, participant, observers bool, cmd func(*state))


This enables you to wrap any command method and control who receives messages.
As an example, when using the LOOK command observers would see:


  You see Diddymus looking around.


However the MOVE command uses the LOOK command to describe the location you
enter. In this case observers would see:


  You see Diddymus enter.
  You see Diddymus looking around.


You don't need to see the second message, which can get a bit annoying. By
wrapping the call to Look with silence we can supress messages to participants
and observers:


  // Instead of this...
  s.Look()

  // We can do this...
  s.silent(false, true, true, Look)


The three boolean flags indicate who to silence: actor, participant and / or
observers. Then you specify the command method. In the case above, the actor
is not silenced but the participant and observers are - so only the actor will
see the output of the LOOK command.

All of the attributes have been updated as well. All attribute finders now
return a typed nil instead of an untyped nil and all methods can handle a nil
receiver. This has cleaned up a lot of the code implementing commands as we
can now chain other methods to finders. Another fun example:


  // Instead of...
  who := "Someone"
  if a := attr.FindName(s.actor); a != nil {
    who = a.Name()
  }

  // We can now write...
  who := attr.FindName(s.actor).Name("someone")


I picked that example to show another update: the Name method now takes a
default / preset name. So if there is no name attribute available - or it has
not been set - you can use a preset "someone", "something", "somewhere" as
appropriate instead.

The default name is called 'preset' rather than 'default' as default is a
reserved keyword and cannot be used as a variable name:


  func (n *Name) Name(preset string) string


Another use for the preset is that you can use the alias for something as the
name until you can find out it's actual name. Example time again:

  // name starts as what the player typed, e.g. BALL
  name := s.word[0]

  // search for "BALL"
  what := attr.FindInventory(where).Search(name)

  // "BALL" found?
  if what == nil {
    // If not found we can display "You see no 'BALL' here."
    s.msg.actor.WriteJoin("You see no '", name, "' here.")
    return
  }

  // get actuall name of the "BALL" e.g. "A small rubber ball"
  name = attr.FindName(what).Name("something")

  // Display "You drop a small rubber ball."
  s.msg.actor.WriteJoin("You drop", name, ".")


I think that's all of the changes covered with more on the way soon, I hope.

--
Diddymus


  Up to Main Index                          Up to Journal for February, 2016