Documentation ¶
Overview ¶
Package core handles all of the main processing of items and player commands in WolfMUD. All items are represented via the Thing type with capabilities and settings implemented as Thing.xxx values. The short names Is, As, In etc. were chosen to be meaningful and easily readable in code.
Index ¶
- Constants
- Variables
- func Config(c config.Config)
- func EventCount() (count int)
- func LimitedMatch(words []string, where ...*Thing) (results, remaining []string)
- func Match(words []string, where ...*Thing) (results []string)
- func Message(A, D *Thing, msg string) (a, d, o string)
- func NewState(t *Thing) *state
- func Pronoun(actor *Thing, p string) string
- func RegisterCommandHandlers()
- func StripMatch(what *Thing, input string) string
- func ThingCount() (count int)
- type Events
- type Thing
- func (t *Thing) Cancel(event eventKey)
- func (t *Thing) Copy(deep bool) *Thing
- func (t *Thing) Dump(w io.Writer, width int)
- func (t *Thing) Free()
- func (t *Thing) Init()
- func (t *Thing) InitOnce(parent *Thing)
- func (t *Thing) Junk()
- func (t *Thing) Marshal() recordjar.Record
- func (t *Thing) Schedule(event eventKey)
- func (t *Thing) Spawn() *Thing
- func (t *Thing) Suspend(event eventKey)
- func (t *Thing) Unmarshal(r recordjar.Record)
- type Things
- Bugs
Constants ¶
const ( Container isKey = 1 << iota // A container, allows PUT/TAKE Dark // A dark location Freed // Thing has been freed for GC HasBody // Item has a body (Any[Body] can be empty) Holding // Item is being held Location // Item is a location NPC // An NPC Narrative // A narrative item Open // An open item (e.g. door) Player // Is a player Spawnable // Is item spawnable? Start // A starting location Wait // Container reset wait for inventory? Wielding // Item is being wielded Wearing // Item is being worn )
Constants for use as bitmasks with the Thing.Is field.
const ( BadAsKey asKey = iota Account // MD5 hash of player's account Barrier // A barrier, value is direction of exit blocked ("E") Blocker // Name of direction being blocked ("E") Description // Item's description DynamicAlias // "PLAYER" or unset, "SELF" for actor performing a command DynamicQualifier // Situation dependant e.g. GET sets "MY",DROP deleted "MY" Gender // Gender of a player or NPC Name // Item's name OnCleanup // Custome cleanup message for an item OnReset // Custom reset message for an item Password // Salted SHA512 hash of the account password Ref // Item's original reference (zone:ref or ref) Salt // Salt used for the account password StatusSeq // Escape sequence for writing status updates TheName // Item's name with a/an/some prefix changed to 'the' TriggerType // Type of trigger event to send UID // Item's unique identifier UName // Name with the initial character upper-cased UTheName // TheName with the initial character upper-cased VetoClose // Veto CLOSE command VetoCombat // Veto fighting commands VetoDrop // Veto for DROP command VetoGet // Veto for GET command VetoHold // Veto HOLD command VetoJunk // Veto for JUNK command VetoOpen // Veto OPEN command VetoPut // Veto PUT command for item VetoPutIn // Veto for PUT command into container VetoRead // Veto READ command VetoRemove // Veto REMOVE command VetoTake // Veto TAKE command for item VetoTakeOut // Veto for TAKE command from container VetoWear // Veto WEAR command VetoWield // Veto WIELD command Writing // Description of writing on an item Zone // Zone item's definition loaded from )
Constants for use as keys in a Thing.As field.
const ( BadAnyKey anyKey = iota Alias // Aliases for an item BarrierAllow // Aliases allowed to pass barrier BarrierDeny // Aliases denied to pass barrier Body // Body slots available to an item Holdable // Body slots required to hold item OnAction // Actions that can be performed OnCombat // Combat actions that can be performed Opponents // UID of opponents being defended against Permissions // Permissions a player has Qualifier // Alias qualifiers Wearable // Body slots required to wear item Wieldable // Body slots required to wield item )
Constants for Thing.Any keys
const ( BadIntKey intKey = iota // Events ActionAfter // How often an action event should occur ActionJitter // Maximum random delay to add to ActionAfter ActionDueAt // Time a scheduled Action is due ActionDueIn // Time remaining for Action CleanupAfter // How soon a clean-up event should occur CleanupJitter // Maximum random delay to add to CleanupAfter CleanupDueAt // Time a scheduled clean-up is due CleanupDueIn // Time remaining for clean-up CombatAfter // How soon a clean-up event should occur CombatJitter // Maximum random delay to add to CleanupAfter CombatDueAt // Time a scheduled clean-up is due CombatDueIn // Time remaining for clean-up HealthAfter // How soon a healing event should occur HealthJitter // Maximum random delay to add to HealthAfter HealthDueAt // Time a scheduled healing event is due HealthDueIn // Time remaining for healing event ResetAfter // How soon a reset event should occur ResetJitter // Maximum random delay to add to TesetAfter ResetDueAt // Time a scheduled reset is due ResetDueIn // Time remaining for reset TriggerAfter // How soon a trigger should occur TriggerJitter // Maximum random delay to add to trigger TriggerDueAt // Time a scheduled trigger event is due TriggerDueIn // Time remaining for trigger event // Non-events Armour // Armour rating Created // Timestamp of when item (player) created DamageFixed // Fixed amount of damage for an actor/item DamageRandom // [0-DamageRandom] of random damage for an actor/item HealthCurrent // Current health of a player/mobile HealthMaximum // Maximum health a player/mobile heals up to. HealthRestore // Health restored per healing event )
Constants for Thing.Int keys
NOTE: See also comments for eventKey constants.
const ( AfterOffset intKey = iota JitterOffset DueAtOffset DueInOffset )
Standard offsets for Event related values. Given an eventKey we can add the offsets to get the After, Jitter, DueAt and DueIn values from Thing.Int for an event.
const ( Action eventKey = eventKey(ActionAfter) Cleanup = eventKey(CleanupAfter) Combat = eventKey(CombatAfter) Health = eventKey(HealthAfter) Reset = eventKey(ResetAfter) Trigger = eventKey(TriggerAfter) )
Constants for Thing.Events keys
NOTE: Events map to Thing.Int values. The intKey constants for an event's After and Jitter values should be consecutive as we assume After = eventKey and Jitter = eventKey+1.
const ( BadRefKey refKey = iota // Exit directions should always be consecutive constants in given order North Northeast East Southeast South Southwest West Northwest Up Down Opponent // Opponent being directly attacked Origin // Where a unique item resets to Where // Where an item is )
Constants for Thing.Ref keys
Useful masks for groups of constants for checking multiple flags.
Variables ¶
var ( BWL sync.Mutex WorldStart []*Thing // Starting locations World = make(Things) // All top level locations Players = make(Things) // Current in-game players )
World contains all of the top level locations for the current game world. WorldStart only contains valid player starting locations. Both are protected by the BWL (Big World Lock).
var ( // NameToDir maps a long or short direction name to its Thing.As constant. NameToDir = map[string]refKey{ "N": North, "NE": Northeast, "E": East, "SE": Southeast, "S": South, "SW": Southwest, "W": West, "NW": Northwest, "U": Up, "D": Down, "NORTH": North, "NORTHEAST": Northeast, "EAST": East, "SOUTHEAST": Southeast, "SOUTH": South, "SOUTHWEST": Southwest, "WEST": West, "NORTHWEST": Northwest, "UP": Up, "DOWN": Down, } // DirToName maps a Thing.As direction constant to the direction's long name. DirToName = map[refKey]string{ North: "north", Northeast: "northeast", East: "east", Southeast: "southeast", South: "south", Southwest: "southwest", West: "west", Northwest: "northwest", Up: "up", Down: "down", } // DirRefToAs maps a Thing.Ref direction to a Thing.As direction DirRefToAs = map[refKey]asKey{ North: _North, Northeast: _Northeast, East: _East, Southeast: _Southeast, South: _South, Southwest: _Southwest, West: _West, Northwest: _Northwest, Up: _Up, Down: _Down, } // ReverseDir maps a Thing.Ref direction to its opposite direction ReverseDir = map[refKey]refKey{ North: South, Northeast: Southwest, East: West, Southeast: Northwest, South: North, Southwest: Northeast, West: East, Northwest: Southeast, Up: Down, Down: Up, } )
Functions ¶
func Config ¶
Config sets up package configuration for settings that can't be constants. It should be called by main, only once, before anything else starts. Once the configuration is set it should be treated as immutable an not changed.
func EventCount ¶
func EventCount() (count int)
EventCount returns the current number of in-flight/active events.
func LimitedMatch ¶
LimitedMatch works in the same way as Match except that it stops after the first match/non-match and returns the unused, remaining input words. The first match/non-match will consume words from the end of the passed input word slice.
NOTE: Although LimitedMatch stops after the first match/non-match it may produce multiple results. For example, if we have a red, a green and two blue balls then:
LimitedMatch( []string{"RED", "BALL", "ALL", "BLUE", "BALL"}), s.actor, )
Would return one match, it being "all blue ball" with the results being the two blue balls. In this case LimitedMatch would return, for example:
[]string{"#UID-10A", "#UID-10E"} and []string{"RED", "BALL"}
func Match ¶
Match attempts to itentify items in the passed Thing's inventory by matching the passed list of words with the item aliases and qualifiers. Match returns a slice containing both good and bad matches. Good matches are always single words containing the UID of the matched item and always start with '#UID-'. Bad matches contain one or more of the input words that could not be matched.
For example, assuming we have one red ball, one green ball and two blue balls then in the following:
Match( []string{"RED", "BALL", "GREEN", "FROG", "ALL", "BLUE", "BALL"}), s.actor, )
Might return:
[]string{"#UID-106", "GREEN FROG", "#UID-10A", "#UID-10E"}
By default, when multiple items match an alias or qualifier+alias, Match will return the first matching item. For example, []string{"BLUE", "BALL"} would return the UID of the first blue ball matched. This can be changed with the use of special prefix modifiers.
Special Modifiers ¶
A modifier may be used before a qualifier or alias to effect the matches that are returned. For example:
[]string{"ALL", "BALL"} []string{"ALL", "BLUE", "BALL"}
The currently supported modifiers are:
ALL - all matches LAST - the last item matched ANY - one random item matched N/Nth - the Nth item matched (or last item if N > matches)
NOTE: For performance reasons, if a thing being searched is considered crowded then we don't include everyone in the crowd in the search.
TODO(diddymus): Add 'see also' pointing to docs/ files.
BUG(diddymus): Nth does not care what the suffix is, 2nd and 2rd are both seen as valid modifiers.
BUG(diddyus): Does not support ranges yet. For example 'which 2-4 ball' for the 2nd, 3rd and 4th balls.
func Pronoun ¶ added in v0.0.21
Pronoun returns the correct pronoun for a given actor's gender. This allows, for example, messages to be defined generally with neutral pronouns. This function will then turn the neutral pronoun into one specific to the actor's gender. If the actor does not have a gender, or the gender is invalid, a generic 'it' is assumed.
NOTE: messages should be defined using neutral pronouns as they are unique.
func RegisterCommandHandlers ¶
func RegisterCommandHandlers()
RegisterCommandHandlers initialises the commandHandlers, commandNames and eventCommands. It needs to be called before any player, admin or scripting commands are used. RegisterCommandHandlers should be called while core.BWL is held.
func StripMatch ¶
StripMatch removes the leading stopwords, modifiers, qualifiers and alias from the input string that would have been used to match the passed what.
For example, assuming the player state for "tell any of the guard the vendor is here!":
s.input: any of the guard the vendor is here s.word: ANY GUARD VENDOR HERE!
The matcher can match "ANY GUARD", however there is a problem. How do we relate "VENDOR HERE" back to the original input of "any of the guard the vendor is here" so that we are left with what was being said, "the vendor is here"? This is where StripMatch can be used to remove the text that would have been used to match "ANY GUARD". In this case "any of the guard" would be removed, returning "the vendor is here".
Types ¶
type Events ¶
Events is used to store currently in-flight events for a Thing.
type Thing ¶
type Thing struct { As map[asKey]string // Single value for a key Any map[anyKey][]string // One or more values for a key Int map[intKey]int64 // Integer values, counts and quantities Ref map[refKey]*Thing // References to other Thing (e.g. Where) In Things // Items in a Thing (inventory) Out Things // Items out of play in a Thing Who Things // Who is here? Players @ location Is isKey // Bit flags for capabilities/state Event Events // In-flight event timers }
Thing is used to represent any and all items in the game world.
NOTE: If new fields are added to Thing they should be catered for in the NewThing and Free methods.
NOTE: Times and durations stored in Int should be in nanoseconds.
func NewThing ¶
func NewThing() *Thing
NewThing returns a new initialised Thing with no properties set.
TODO(diddymus): UID needs adding as an alias once we have multiple aliases.
func (*Thing) Cancel ¶
func (t *Thing) Cancel(event eventKey)
Cancel an event for a Thing. The remaining time for the event is not recorded. If the event is rescheduled the timers will start over. A suspended event may be subsequently cancelled.
func (*Thing) Copy ¶
Copy returns a duplicate of the receiver Thing with only the UID and Who being different. We don't duplicate Who as this would duplicate players. If deep is set to true the Thing's inventory will be copied recursively.
func (*Thing) Dump ¶
Dump will write a pretty ASCII tree representing the details of a Thing. A simple, single item:
`- 0xc00000e048 *core.Thing - CAT |- Name - the tavern cat |- Description - The tavern cat is a ball of fur with one golden eye, the | other eye replaced by a large scar. It senses you | watching it and returns your gaze with a steady one of | its own. |- Is - 00000000000000000000000000001000 (NPC) |- As - len: 1 | `- [11] Alias: CAT `- In - len: 0, nil: true
A container with an item in its inventory:
`- 0xc00009c008 *core.Thing - BAG |- Name - a bag |- Description - This is a simple cloth bag. |- Is - 00000000000000000000000000010000 (Container) |- As - len: 1 | `- [11] Alias: BAG `- In - len: 1, nil: false `- 0xc00009c010 *core.Thing - APPLE |- Name - an apple |- Description - This is a red apple. |- Is - 00000000000000000000000000000000 () |- As - len: 1 | `- [11] Alias: APPLE `- In - len: 0, nil: true
func (*Thing) Free ¶
func (t *Thing) Free()
Free recursively unlinks everything from a Thing. This is not really necessary, but makes it easier for the garbage collector.
func (*Thing) Init ¶
func (t *Thing) Init()
Init is used for the repeatable setup or resetting of a Thing.
func (*Thing) InitOnce ¶
InitOnce performs final setup for a Thing placed into the world. The Thing will have access to its inventory and surroundings. The passed parent is the UID of the containing inventory, for locations themselves this will be an empty string. The parent is enabled before any inventory items. As its name implies InitOnce is only called once for a Thing - when it is first put into the world.
TODO(diddymus): Handle DOOR/blockers as part of location definitions?
func (*Thing) Junk ¶
func (t *Thing) Junk()
Junk removes an item from the world and either schedules it to reset if it is unique or spawnable, otherwise it is freed for the garbage collector. If the item has inventory it is also junked.
func (*Thing) Marshal ¶
Marshal saves data from the Thing into the returned Record.
BUG(diddymus): Doors save twice as we don't know what side we are on. BUG(diddymus): Live saves don't record a due_in for events. This could be calculated from due_at.
func (*Thing) Schedule ¶
func (t *Thing) Schedule(event eventKey)
Schedule the specified event for a Thing. If the event is already in-flight it will be cancelled and the new event scheduled. A scheduled event may be suspended, and then resumed by rescheduling it. A scheduled event may be cancelled, in which case rescheduling will cause the timers to start over.
func (*Thing) Spawn ¶
Spawn returns a copy of a spawnable Thing or the original if not spawnable. The returned copy will not be spawnable. If the original contains any spawnable items they will remain spawnable. If the original contains any non-spawnable items they will be moved to the copy.
func (*Thing) Suspend ¶
func (t *Thing) Suspend(event eventKey)
Suspend an event for a Thing. If the event is not in-flight no action is taken. Suspending an in-flight event will record the time remaining before it fires so that the timers can be resumed when the event is rescheduled. A suspended event may be subsequently cancelled.
Notes ¶
Bugs ¶
Junking a unique container junks all its content.
Blockers, such as doors, are currently ignored.
Nth does not care what the suffix is, 2nd and 2rd are both seen as valid modifiers.
Does not support ranges yet. For example 'which 2-4 ball' for the 2nd, 3rd and 4th balls.
Players will be mistaken for NPCs when they are loaded. Currently the client.assemblePlayer method will correct the flags.
Doors save twice as we don't know what side we are on.
Live saves don't record a due_in for events. This could be calculated from due_at.
This will save the door twice as we don't know which side we are on.
This function is not Unicode safe and embeded line feeds will probably produce an undesireable result.