core

package
v0.0.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 14, 2022 License: BSD-2-Clause Imports: 21 Imported by: 0

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

View Source
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.

View Source
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.

View Source
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

View Source
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.

View Source
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.

View Source
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.

View Source
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

View Source
const (
	Using isKey = Holding | Wearing | Wielding
)

Useful masks for groups of constants for checking multiple flags.

Variables

View Source
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).

View Source
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

func Config(c config.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

func LimitedMatch(words []string, where ...*Thing) (results, remaining []string)

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

func Match(words []string, where ...*Thing) (results []string)

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 Message added in v0.0.21

func Message(A, D *Thing, msg string) (a, d, o string)

func NewState

func NewState(t *Thing) *state

func Pronoun added in v0.0.21

func Pronoun(actor *Thing, p string) string

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

func StripMatch(what *Thing, input string) string

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".

func ThingCount

func ThingCount() (count int)

ThingCount returns the current number of Thing making up the game world.

Types

type Events

type Events map[eventKey]*time.Timer

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

func (t *Thing) Copy(deep bool) *Thing

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

func (t *Thing) Dump(w io.Writer, width int)

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

func (t *Thing) InitOnce(parent *Thing)

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

func (t *Thing) Marshal() recordjar.Record

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

func (t *Thing) Spawn() *Thing

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.

func (*Thing) Unmarshal

func (t *Thing) Unmarshal(r recordjar.Record)

Unmarshal loads data from the passed Record into a Thing.

BUG(diddymus): Players will be mistaken for NPCs when they are loaded. Currently the client.assemblePlayer method will correct the flags.

type Things

type Things map[string]*Thing

Things represents a group of Thing indexed by UID.

func (Things) Sort

func (t Things) Sort() []*Thing

Sort returns the receiver Things as a slice of the Things sorted by UID.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL