Up to Main Index                          Up to Journal for November, 2020

                    JOURNAL FOR SUNDAY 8TH NOVEMBER, 2020
______________________________________________________________________________

SUBJECT: Introducing @refs, because I hate having to repeat myself
   DATE: Sun  8 Nov 18:21:14 GMT 2020

The release of v0.0.17 for Halloween seemed to go well. I didn’t hear any
screams — maybe a few cackles and maniacal laughs, but that’s Halloween :)

Since then I’ve been working on adding a feature just for zone authors, and
because I’m lazy :P

In v0.0.15 the Body attribute was added, and their definitions are very
verbose to write out in zone files. A typical full body definition might be:


  Body: ANKLE→2 BACK→1 CHEST→1 EAR→2 ELBOW→2 EYE→2 FACE→1 FINGER→8 FOOT→2
        HAND→2 HEAD→1 KNEE→2 LOWER_ARM→2 LOWER_LEG→2 LOWER_LIP→1 MOUTH→1
        NECK→1 NOSE→1 PELVIS→1 SHOULDER→2 THUMB→2 UPPER_ARM→2 UPPER_LEG→2
        UPPER_LIP→1 WAIST→1 WRIST→2


Typically you would define a Body, then copy‘n’paste it throughout your zone
file for all of the humanoid mobiles. Then you’d notice a mistake, a typo, a
left out body part. Now you have to edit all of the places where you did a
copy‘n’paste — and hope you don’t miss anything. In short a nightmare. Did I
mention I’m lazy? I don’t want to go through all that, I don’t even want to do
the copy‘n’paste in the first place!

Wouldn’t it be nice to have a standard Body definition and just have a simple
reference to it wherever you want to use it? I present to you @refs…


  %%
     // Standard definitions for humanoids
   Ref: HUMANOID
  Body: ANKLE→2 BACK→1 CHEST→1 EAR→2 ELBOW→2 EYE→2 FACE→1 FINGER→8 FOOT→2
        HAND→2 HEAD→1 KNEE→2 LOWER_ARM→2 LOWER_LEG→2 LOWER_LIP→1 MOUTH→1
        NECK→1 NOSE→1 PELVIS→1 SHOULDER→2 THUMB→2 UPPER_ARM→2 UPPER_LEG→2
        UPPER_LIP→1 WAIST→1 WRIST→2
  %%
   Ref: M1
  Body: @HUMANOID
      :
      :
  %%
   Ref: M2
  Body: @HUMANOID
      :
      :
  %%


An @ref or ‘at reference’ or simply ‘at ref’ points to a definition at another
reference — hence the naming. In the above example the Body field of M1 and M2
use an @ref of ‘@HUMANOID’. This locates the corresponding Body field in the
record with a reference of HUMANOID and replaces the text @HUMANOID with the
data found. Think of it as the definition for Body is found at the definition
for HUMANOID.

Blissful laziness, we define the HUMANOID Body once and just reference it :)

As it’s only the @ref that is replaced, other data may be included on the
field as well. For example, we could define some standard default durations
for events:


  %%
        // Some default definitions
      Ref: DEFAULT
    Reset: AFTER→5m JITTER→5m
  Cleanup: AFTER→5m JITTER→5m
   Action: AFTER→30s JITTER→30s
     Door: RESET→1m JITTER→1m
  %%


Then we can define mobiles, items and locations that use them:


  %%
      Ref: O1
     Door: @DEFAULT EXIT→E
         :
         :
  %%
      Ref: O2
    Reset: @DEFAULT SPAWN
         :
         :
  %%


Notice that the O1 Door field specifies an extra ‘EXIT→E’ and the O2 Reset
field specifies and extra ‘SPAWN’. When the @refs are expanded the records
look like this:


  %%
      Ref: O1
     Door: RESET→1m JITTER→1m EXIT→E
         :
         :
  %%
      Ref: O2
    Reset: AFTER→5m JITTER→5m SPAWN
         :
         :
  %%


An @ref may also include other @refs. For example we could add our HUMANOID
Body definition to our default definitions:


  %%
        // Some default definitions
      Ref: DEFAULT
    Reset: AFTER→5m JITTER→5m
  Cleanup: AFTER→5m JITTER→5m
   Action: AFTER→30s JITTER→30s
     Door: RESET→1m JITTER→1m
     Body: @HUMANOID
  %%
     // Standard definitions for humanoids
   Ref: HUMANOID
  Body: ANKLE→2 BACK→1 CHEST→1 EAR→2 ELBOW→2 EYE→2 FACE→1 FINGER→8 FOOT→2
        HAND→2 HEAD→1 KNEE→2 LOWER_ARM→2 LOWER_LEG→2 LOWER_LIP→1 MOUTH→1
        NECK→1 NOSE→1 PELVIS→1 SHOULDER→2 THUMB→2 UPPER_ARM→2 UPPER_LEG→2
        UPPER_LIP→1 WAIST→1 WRIST→2
  %%


If we then use ‘Body: @DEFAULT’ it will be expanded with the DEFAULT ‘Body:
@HUMANOID’, which in turn will be expanded with the HUMANOID Body definition.

Note also that you can use either ‘Body: @DEFAULT’ or ‘Body: @HUMANOID’ when
defining mobiles. Using ‘Body: @DEFAULT’ the body can be easily pointed to a
different definition by changing the DEFAULT’s ‘Body: @HUMANOID’. Using ‘Body:
@HUMANOID’ you either need to update HUMANOID’s Body definition or change all
of the mobiles using ‘Body: @HUMANOID’ to reference a different definition.

Is that all @refs can do? Well they have one more trick. You can use multiple
@refs for a field. For example, we could set up some default actions:


  %%
       Ref: CHAT
  OnAction: SAY Hello.
          : SAY A lot of weather we've been having recently.
          : Say Now where did I put that...
          : SAY Now let me see...
          : SAY So much to do
          :
          :
  %%
       Ref: IDLE
  OnAction: $ACT starts to whistle a little ditty.
          : $ACT watches you.
          : $ACT stifles a yawn.
          : $ACT sighs.
          : EXAM PLAYER
          :
          :
  %%
       Ref: BUSY
  OnAction: SAY So much to do...
          : SAY I need a break.
          : $ACT bustles about.
          :
          :
  %%
       Ref: SHOPKEEPER
  OnAction: $ACT starts sweeping the floor.
          : $ACT tidies up a bit.
          : $ACT watches you as you browse around the shop.
          : SAY See anything you like?
          :
          :
  %%


We can then define some mobiles to use different combinations of these
actions:


  %%
         // A busy, chatty shopkeeper
       Ref: M1
  OnAction: @CHAT
          : @BUSY
          : @SHOPKEEPER
 %%
         // A very, chatty shopkeeper
       Ref: M1
  OnAction: @CHAT
          : @CHAT
          : @CHAT
          : @SHOPKEEPER
  %%
         // A busy shopkeeper with custom actions
       Ref: M1
  OnAction: @BUSY
          : @SHOPKEEPER
          : $ACT starts to whistle and hum softly to himself.
          : $ACT idly dusts a few random items.
          : $ACT cautiously watches you as you browse around the store.
  %%


That is all there is to know about @refs. You can point to a definition, nest
@refs and have multiple @refs on a field. Where it makes sense you can also
repeat an @ref multiple times for a field. With this new flexibility comes a
price — each zone file can take 1 or 2 milliseconds longer[1] to load when
starting the server :P

For those interested in the code, there is a new zone pre-processor to handle
@refs in zones/preprocessor.go that runs when the server starts and zone files
are loaded. It will warn you about missing fields and definitions and detects
infinite loops[2] for nested @refs.

The pre-processor is designed to be extensible. I’m thinking of adding an
‘include file’ feature to zone files — at the moment you need standard
definitions in each zone file, it would be better to have a single file for
standard definitions and then pull it in to each zone file. I’m also thinking
of adding an @ref field for when you just want to reference field definitions
and not use multiple @refs or add extra data:


  %%
         // Example of an @ref field '@DEFAULT' that copies the BODY,
         // INVENTORY, RESET fields from the DEFAULT definition. Also copies
         // ACTION and ONACTION fields from the SPECIAL definition.
       Ref: M1
  @DEFAULT: BODY INVENTORY RESET
  @SPECIAL: ACTION ONACTION
          :
          :
   %%


The new @ref feature is now out on the public dev branch. Additional details
and examples can be found in the docs/zone-files.txt documentation. The sample
sample zone files have not been updated yet as I’m working on tidying them up
and figuring out some sensible definitions people can look over.

--
Diddymus

  [1] Well it’s 1 or 2 milliseconds on my (2011 sandy bridge) quad core
      i5-2400 @ 3.1GHz desktop with spinning rust hard drives. I like this
      processor as it’s quad core without hyper-threading.

  [2] That feature alone called for a redesign of the pre-processor and two
      rewrites of the code. The things I do… :|


  Up to Main Index                          Up to Journal for November, 2020