evennia.contrib.rpg.buffs.buff

Buffs - Tegiminis 2022

A buff is a timed object, attached to a game entity, that modifies values, triggers code, or both. It is a common design pattern in RPGs, particularly action games.

This contrib gives you a buff handler to apply to your objects, a buff class to extend them, a sample property class to show how to automatically check modifiers, some sample buffs to learn from, and a command which applies buffs.

Installation

Assign the handler to a property on the object, like so.

@lazy_property
def buffs(self) -> BuffHandler:
    return BuffHandler(self)

Using the Handler

To make use of the handler, you will need:

  • Some buffs to add. You can create these by extending the BaseBuff class from this module. You can see some examples in samplebuffs.py.

  • A way to add buffs to the handler. You can see a basic example of this in the CmdBuff command in this module.

Applying a Buff

Call the handler add(BuffClass) method. This requires a class reference, and also contains a number of optional arguments to customize the buff’s duration, stacks, and so on.

self.buffs.add(StrengthBuff)    # A single stack of StrengthBuff with normal duration
self.buffs.add(DexBuff, stacks=3, duration=60)  # Three stacks of DexBuff, with a duration of 60 seconds
self.buffs.add(ReflectBuff, to_cache={'reflect': 0.5})  # A single stack of ReflectBuff, with an extra cache value

Modify

Call the handler check(value, stat) method wherever you want to see the modified value. This will return the value, modified by and relevant buffs on the handler’s owner (identified by the stat string). For example:

# The method we call to damage ourselves
def take_damage(self, source, damage):
    _damage = self.buffs.check(damage, 'taken_damage')
    self.db.health -= _damage

Trigger

Call the handler trigger(triggerstring) method wherever you want an event call. This will call the at_trigger hook method on all buffs with the relevant trigger.

def Detonate(BaseBuff):
    ...
    triggers = ['take_damage']
    def at_trigger(self, trigger, *args, **kwargs)
        self.owner.take_damage(100)
        self.remove()

def Character(Character):
    ...
    def take_damage(self, source, damage):
        self.buffs.trigger('take_damage')
        self.db.health -= _damage

Tick

Ticking a buff happens automatically once applied, as long as the buff’s tickrate is more than 0.

def Poison(BaseBuff):
    ...
    tickrate = 5
    def at_tick(self, initial=True, *args, **kwargs):
        _dmg = self.dmg * self.stacks
        if not initial:
            self.owner.location.msg_contents(
                "Poison courses through {actor}'s body, dealing {damage} damage.".format(
                    actor=self.owner.named, damage=_dmg
                )
            )

Buffs

A buff is a class which contains a bunch of immutable data about itself - such as tickrate, triggers, refresh rules, and so on - and which merges mutable data in from the cache when called.

Buffs are always instanced when they are called for a method. To access a buff’s properties and methods, you should do so through this instance, rather than directly manipulating the buff cache on the object. You can modify a buff’s cache through various handler methods instead.

You can see all the features of the BaseBuff class below, or browse samplebuffs.py to see how to create some common buffs. Buffs have many attributes and hook methods you can overload to create complex, interrelated buffs.

evennia.contrib.rpg.buffs.buff.random() → x in the interval [0, 1).
class evennia.contrib.rpg.buffs.buff.BaseBuff(handler, buffkey, cache)[source]

Bases: object

key = 'template'
name = 'Template'
flavor = 'Template'
visible = True
triggers = []
handler = None
start = 0
duration = -1
playtime = False
refresh = True
unique = True
maxstacks = 1
stacks = 1
tickrate = 0
mods = []
cache = {}
property ticknum

Returns how many ticks this buff has gone through as an integer.

property owner

Return this buff’s owner (the object its handler is attached to)

property timeleft

Returns how much time this buff has left. If -1, it is permanent.

property ticking

Returns if this buff ticks or not (tickrate => 1)

property stacking

Returns if this buff stacks or not (maxstacks > 1)

__init__(handler, buffkey, cache) → None[source]
Parameters
  • handler – The handler this buff is attached to

  • buffkey – The key this buff uses on the cache

  • cache – The cache dictionary (what you get if you use handler.buffcache.get(key))

conditional(*args, **kwargs)[source]

Hook function for conditional evaluation.

This must return True for a buff to apply modifiers, trigger effects, or tick.

remove(loud=True, expire=False, context=None)[source]

Helper method which removes this buff from its handler. Use dispel if you are dispelling it instead.

Parameters
  • loud – (optional) Whether to call at_remove or not (default: True)

  • expire – (optional) Whether to call at_expire or not (default: False)

  • delay – (optional) How long you want to delay the remove call for

  • context – (optional) A dictionary you wish to pass to the at_remove/at_expire method as kwargs

dispel(loud=True, delay=0, context=None)[source]

Helper method which dispels this buff (removes and calls at_dispel).

Parameters
  • loud – (optional) Whether to call at_remove or not (default: True)

  • delay – (optional) How long you want to delay the remove call for

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel method as kwargs

pause(context=None)[source]

Helper method which pauses this buff on its handler.

Parameters

context – (optional) A dictionary you wish to pass to the at_pause method as kwargs

unpause(context=None)[source]

Helper method which unpauses this buff on its handler.

Parameters

context – (optional) A dictionary you wish to pass to the at_unpause method as kwargs

reset()[source]

Resets the buff start time as though it were just applied; functionally identical to a refresh

update_cache(to_cache: dict)[source]

Updates this buff’s cache using the given values, both internally (this instance) and on the handler.

Parameters

to_cache – The dictionary of values you want to add to the cache

at_init(*args, **kwargs)[source]

Hook function called when this buff object is initialized.

at_apply(*args, **kwargs)[source]

Hook function to run when this buff is applied to an object.

at_remove(*args, **kwargs)[source]

Hook function to run when this buff is removed from an object.

at_dispel(*args, **kwargs)[source]

Hook function to run when this buff is dispelled from an object (removed by someone other than the buff holder).

at_expire(*args, **kwargs)[source]

Hook function to run when this buff expires from an object.

at_pre_check(*args, **kwargs)[source]

Hook function to run before this buff’s modifiers are checked.

at_post_check(*args, **kwargs)[source]

Hook function to run after this buff’s mods are checked.

at_trigger(trigger: str, *args, **kwargs)[source]

Hook for the code you want to run whenever the effect is triggered. Passes the trigger string to the function, so you can have multiple triggers on one buff.

at_tick(initial: bool, *args, **kwargs)[source]

Hook for actions that occur per-tick, a designer-set sub-duration. initial tells you if it’s the first tick that happens (when a buff is applied).

at_pause(*args, **kwargs)[source]

Hook for when this buff is paused

at_unpause(*args, **kwargs)[source]

Hook for when this buff is unpaused.

class evennia.contrib.rpg.buffs.buff.Mod(stat: str, modifier: str, value, perstack=0.0)[source]

Bases: object

A single stat mod object. One buff or trait can hold multiple mods, for the same or different stats.

__init__(stat: str, modifier: str, value, perstack=0.0) → None[source]
Parameters
  • stat – The stat the buff affects. Normally matches the object attribute name

  • mod – The modifier the buff applies. “add” for add/sub or “mult” for mult/div

  • value – The value of the modifier

  • perstack – How much is added to the base, per stack (including first).

stat = 'null'
modifier = 'add'
value = 0
perstack = 0
class evennia.contrib.rpg.buffs.buff.BuffHandler(owner, dbkey='buffs', autopause=False)[source]

Bases: object

__init__(owner, dbkey='buffs', autopause=False)[source]
Parameters
  • owner – The object this handler is attached to

  • dbkey – (optional) The string key of the db attribute to use for the buff cache

  • autopause – (optional) Whether this handler autopauses playtime buffs on owning object’s unpuppet

ownerref = None
dbkey = 'buffs'
autopause = False
property owner

The object this handler is attached to.

property buffcache

The object attribute we use for the buff cache. Auto-creates if not present.

property traits

All buffs on this handler that modify a stat.

property effects

All buffs on this handler that trigger off an event.

property playtime

All buffs on this handler that only count down during active playtime.

property paused

All buffs on this handler that are paused.

property expired

All buffs on this handler that have expired (no duration or no stacks).

property visible

All buffs on this handler that are visible.

property all

Returns dictionary of instanced buffs equivalent to ALL buffs on this handler, regardless of state, type, or anything else.

add(buff: evennia.contrib.rpg.buffs.buff.BaseBuff, key: str = None, stacks=0, duration=None, source=None, to_cache=None, context=None, *args, **kwargs)[source]

Add a buff to this object, respecting all stacking/refresh/reapplication rules. Takes a number of optional parameters to allow for customization.

Parameters
  • buff – The buff class type you wish to add

  • key – (optional) The key you wish to use for this buff; overrides defaults

  • stacks – (optional) The number of stacks you want to add, if the buff is stacking

  • duration – (optional) The amount of time, in seconds, you want the buff to last; overrides defaults

  • source – (optional) The source of this buff. (default: None)

  • to_cache – (optional) A dictionary to store in the buff’s cache; does not overwrite default cache keys

  • context – (optional) A dictionary you wish to pass to the at_apply method as kwargs

remove(key, stacks=0, loud=True, dispel=False, expire=False, context=None)[source]

Remove a buff or effect with matching key from this object. Normally calls at_remove, calls at_expire if the buff expired naturally, and optionally calls at_dispel. Can also remove stacks instead of the entire buff (still calls at_remove). Typically called via a helper method on the buff instance, or other methods on the handler.

Parameters
  • key – The buff key

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

remove_by_type(bufftype: evennia.contrib.rpg.buffs.buff.BaseBuff, loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs of a specified type from this object. Functionally similar to remove, but takes a type instead.

Parameters
  • bufftype – The buff class to remove

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

remove_by_stat(stat, loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs modifying the specified stat from this object.

Parameters
  • stat – The stat string to search for

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

remove_by_trigger(trigger, loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs with the specified trigger from this object.

Parameters
  • trigger – The stat string to search for

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

remove_by_source(source, loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs from the specified source from this object.

Parameters
  • source – The source to search for

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

remove_by_cachevalue(key, value=None, loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs with the cachevalue from this object. Functionally similar to remove, but checks the buff’s cache values instead.

Parameters
  • key – The key of the cache value to check

  • value – (optional) The value to match to. If None, merely checks to see if the value exists

  • loud – (optional) Calls at_remove when True. (default: True)

  • dispel – (optional) Calls at_dispel when True. (default: False)

  • expire – (optional) Calls at_expire when True. (default: False)

  • context – (optional) A dictionary you wish to pass to the at_remove/at_dispel/at_expire method as kwargs

clear(loud=True, dispel=False, expire=False, context=None)[source]

Removes all buffs on this handler

get(key: str)[source]

If the specified key is on this handler, return the instanced buff. Otherwise return None. You should delete this when you’re done with it, so that garbage collection doesn’t have to.

Parameters

key – The key for the buff you wish to get

get_all()[source]

Returns a dictionary of instanced buffs (all of them) on this handler in the format {buffkey: instance}

get_by_type(buff: evennia.contrib.rpg.buffs.buff.BaseBuff, to_filter=None)[source]

Finds all buffs matching the given type.

Parameters
  • buff – The buff class to search for

  • to_filter – (optional) A dictionary you wish to slice. If not provided, uses the whole buffcache.

Returns a dictionary of instanced buffs of the specified type in the format {buffkey: instance}.

get_by_stat(stat: str, to_filter=None)[source]

Finds all buffs which contain a Mod object that modifies the specified stat.

Parameters
  • stat – The string identifier to find relevant mods

  • to_filter – (optional) A dictionary you wish to slice. If not provided, uses the whole buffcache.

Returns a dictionary of instanced buffs which modify the specified stat in the format {buffkey: instance}.

get_by_trigger(trigger: str, to_filter=None)[source]

Finds all buffs with the matching string in their triggers.

Parameters
  • trigger – The string identifier to find relevant buffs

  • to_filter – (optional) A dictionary you wish to slice. If not provided, uses the whole buffcache.

Returns a dictionary of instanced buffs which fire off the designated trigger, in the format {buffkey: instance}.

get_by_source(source, to_filter=None)[source]

Find all buffs with the matching source.

Parameters
  • source – The source you want to filter buffs by

  • to_filter – (optional) A dictionary you wish to slice. If not provided, uses the whole buffcache.

Returns a dictionary of instanced buffs which came from the provided source, in the format {buffkey: instance}.

get_by_cachevalue(key, value=None, to_filter=None)[source]

Find all buffs with a matching {key: value} pair in its cache. Allows you to search buffs by arbitrary cache values

Parameters
  • key – The key of the cache value to check

  • value – (optional) The value to match to. If None, merely checks to see if the value exists

  • to_filter – (optional) A dictionary you wish to slice. If not provided, uses the whole buffcache.

Returns a dictionary of instanced buffs with cache values matching the specified value, in the format {buffkey: instance}.

has(buff=None) → bool[source]

Checks if the specified buff type or key exists on the handler.

Parameters

buff – The buff to search for. This can be a string (the key) or a class reference (the buff type)

Returns a bool. If no buff and no key is specified, returns False.

check(value: float, stat: str, loud=True, context=None, trigger=False, strongest=False)[source]

Finds all buffs and perks related to a stat and applies their effects.

Parameters
  • value – The value you intend to modify

  • stat – The string that designates which stat buffs you want

  • loud – (optional) Call the buff’s at_post_check method after checking (default: True)

  • context – (optional) A dictionary you wish to pass to the at_pre_check/at_post_check and conditional methods as kwargs

  • trigger – (optional) Trigger buffs with the stat string as well. (default: False)

  • strongest – (optional) Applies only the strongest mods of the corresponding stat value (default: False)

Returns the value modified by relevant buffs.

trigger(trigger: str, context: dict = None)[source]

Calls the at_trigger method on all buffs with the matching trigger.

Parameters
  • trigger – The string identifier to find relevant buffs. Passed to the at_trigger method.

  • context – (optional) A dictionary you wish to pass to the at_trigger method as kwargs

pause(key: str, context=None)[source]

Pauses the buff. This excludes it from being checked for mods, triggered, or cleaned up. Used to make buffs ‘playtime’ instead of ‘realtime’.

Parameters
  • key – The key for the buff you wish to pause

  • context – (optional) A dictionary you wish to pass to the at_pause method as kwargs

unpause(key: str, context=None)[source]

Unpauses a buff. This makes it visible to the various buff systems again.

Parameters
  • key – The key for the buff you wish to pause

  • context – (optional) A dictionary you wish to pass to the at_unpause method as kwargs

view(to_filter=None) → dict[source]

Returns a buff flavor text as a dictionary of tuples in the format {key: (name, flavor)}. Common use for this is a buff readout of some kind.

Parameters

to_filter – (optional) The dictionary of buffs to iterate over. If none is provided, returns all buffs (default: None)

view_modifiers(stat: str, context=None)[source]

Checks all modifiers of the specified stat without actually applying them. Hits the conditional hook for relevant buffs.

Parameters
  • stat – The mod identifier string to search for

  • context – (optional) A dictionary you wish to pass to the conditional hooks as kwargs

Returns a nested dictionary. The first layer’s keys represent the type of modifier (‘add’ and ‘mult’), and the second layer’s keys represent the type of value (‘total’ and ‘strongest’).

cleanup()[source]

Removes expired buffs, ensures pause state is respected.

class evennia.contrib.rpg.buffs.buff.BuffableProperty(default=None, category=None, strattr=False, lockstring='', autocreate=True)[source]

Bases: evennia.typeclasses.attributes.AttributeProperty

An example of a way you can extend AttributeProperty to create properties that automatically check buffs for you.

at_get(value, obj)[source]

The value returned from the Attribute is passed through this method. It can be used to react to the retrieval or modify the result in some way.

Parameters
  • value (any) – Value returned from the Attribute.

  • obj (object) – Object the attribute is attached to

Returns

any – The value to return to the caller.

Notes

This is will only fire if you actually get the Attribute via this AttributeProperty. That is, if you instead get it via the AttributeHandler (or via .db), you are bypassing this AttributeProperty entirely and this method is never reached.

class evennia.contrib.rpg.buffs.buff.CmdBuff(**kwargs)[source]

Bases: evennia.commands.command.Command

Buff a target.

Usage:

buff <target> <buff>

Applies the specified buff to the target. All buffs are defined in the bufflist dictionary on this command.

key = 'buff'
aliases = []
lock_storage = 'cmd:all();'
search_index_entry = {'aliases': '', 'category': 'builder', 'key': 'buff', 'no_prefix': ' ', 'tags': '', 'text': '\n Buff a target.\n\n Usage:\n buff <target> <buff>\n\n Applies the specified buff to the target. All buffs are defined in the bufflist dictionary on this command.\n '}
help_category = 'builder'
bufflist = {'foo': <class 'evennia.contrib.rpg.buffs.buff.BaseBuff'>}
parse()[source]

Once the cmdhandler has identified this as the command we want, this function is run. If many of your commands have a similar syntax (for example ‘cmd arg1 = arg2’) you should simply define this once and just let other commands of the same form inherit from this. See the docstring of this module for which object properties are available to use (notably self.args).

func()[source]

This is the actual executing part of the command. It is called directly after self.parse(). See the docstring of this module for which object properties are available (beyond those set in self.parse())

evennia.contrib.rpg.buffs.buff.cleanup_buffs(handler: evennia.contrib.rpg.buffs.buff.BuffHandler)[source]

Cleans up all expired buffs from a handler.

evennia.contrib.rpg.buffs.buff.tick_buff(handler: evennia.contrib.rpg.buffs.buff.BuffHandler, buffkey: str, context=None, initial=True)[source]

Ticks a buff. If a buff’s tickrate is 1 or larger, this is called when the buff is applied, and then once per tick cycle.

Parameters
  • handler – The handler managing the ticking buff

  • buffkey – The key of the ticking buff

  • context – (optional) A dictionary you wish to pass to the at_tick method as kwargs

  • initial – (optional) Whether this tick_buff call is the first one. Starts True, changes to False for future ticks