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