<h1>Buffs<aclass="headerlink"href="#buffs"title="Permalink to this headline">¶</a></h1>
<p>Contribution by Tegiminis 2022</p>
<p>A buff is a timed object, attached to a game entity. It is capable of modifying values, triggering code, or both.
It is a common design pattern in RPGs, particularly action games.</p>
<p>Features:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BuffHandler</span></code>: A buff handler to apply to your objects.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BaseBuff</span></code>: A buff class to extend from to create your own buffs.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">BuffableProperty</span></code>: A sample property class to show how to automatically check modifiers.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">CmdBuff</span></code>: A command which applies buffs.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">samplebuffs.py</span></code>: Some sample buffs to learn from.</p></li>
</ul>
<sectionid="quick-start">
<h2>Quick Start<aclass="headerlink"href="#quick-start"title="Permalink to this headline">¶</a></h2>
<p>Assign the handler to a property on the object, like so.</p>
<p>You may then call the handler to add or manipulate buffs like so: <codeclass="docutils literal notranslate"><spanclass="pre">object.buffs</span></code>. See <strong>Using the Handler</strong>.</p>
<sectionid="customization">
<h3>Customization<aclass="headerlink"href="#customization"title="Permalink to this headline">¶</a></h3>
<p>If you want to customize the handler, you can feed the constructor two arguments:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">dbkey</span></code>: The string you wish to use as the attribute key for the buff database. Defaults to “buffs”. This allows you to keep separate buff pools - for example, “buffs” and “perks”.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">autopause</span></code>: If you want this handler to automatically pause playtime buffs when its owning object is unpuppeted.</p></li>
</ul>
<blockquote>
<div><p><strong>Note</strong>: If you enable autopausing, you MUST initialize the property in your owning object’s
<codeclass="docutils literal notranslate"><spanclass="pre">at_init</span></code> hook. Otherwise, a hot reload can cause playtime buffs to not update properly
on puppet/unpuppet. You have been warned!</p>
</div></blockquote>
<p>Let’s say you want another handler for an object, <codeclass="docutils literal notranslate"><spanclass="pre">perks</span></code>, which has a separate database and
respects playtime buffs. You’d assign this new property as so:</p>
<h2>Using the Handler<aclass="headerlink"href="#using-the-handler"title="Permalink to this headline">¶</a></h2>
<p>Here’s how to make use of your new handler.</p>
<sectionid="apply-a-buff">
<h3>Apply a Buff<aclass="headerlink"href="#apply-a-buff"title="Permalink to this headline">¶</a></h3>
<p>Call the handler’s <codeclass="docutils literal notranslate"><spanclass="pre">add</span></code> method. This requires a class reference, and also contains a number of
optional arguments to customize the buff’s duration, stacks, and so on. You can also store any arbitrary value
in the buff’s cache by passing a dictionary through the <codeclass="docutils literal notranslate"><spanclass="pre">to_cache</span></code> optional argument. This will not overwrite the normal
values on the cache.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">buffs</span><spanclass="o">.</span><spanclass="n">add</span><spanclass="p">(</span><spanclass="n">StrengthBuff</span><spanclass="p">)</span><spanclass="c1"># A single stack of StrengthBuff with normal duration</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">buffs</span><spanclass="o">.</span><spanclass="n">add</span><spanclass="p">(</span><spanclass="n">DexBuff</span><spanclass="p">,</span><spanclass="n">stacks</span><spanclass="o">=</span><spanclass="mi">3</span><spanclass="p">,</span><spanclass="n">duration</span><spanclass="o">=</span><spanclass="mi">60</span><spanclass="p">)</span><spanclass="c1"># Three stacks of DexBuff, with a duration of 60 seconds</span>
<spanclass="bp">self</span><spanclass="o">.</span><spanclass="n">buffs</span><spanclass="o">.</span><spanclass="n">add</span><spanclass="p">(</span><spanclass="n">ReflectBuff</span><spanclass="p">,</span><spanclass="n">to_cache</span><spanclass="o">=</span><spanclass="p">{</span><spanclass="s1">'reflect'</span><spanclass="p">:</span><spanclass="mf">0.5</span><spanclass="p">})</span><spanclass="c1"># A single stack of ReflectBuff, with an extra cache value</span>
</pre></div>
</div>
<p>Two important attributes on the buff are checked when the buff is applied: <codeclass="docutils literal notranslate"><spanclass="pre">refresh</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">unique</span></code>.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">refresh</span></code> (default: True) determines if a buff’s timer is refreshed when it is reapplied.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">unique</span></code> (default: True) determines if this buff is unique; that is, only one of it exists on the object.</p></li>
</ul>
<p>The combination of these two booleans creates one of three kinds of keys:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">Unique</span><spanclass="pre">is</span><spanclass="pre">True,</span><spanclass="pre">Refresh</span><spanclass="pre">is</span><spanclass="pre">True/False</span></code>: The buff’s default key.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">Unique</span><spanclass="pre">is</span><spanclass="pre">False,</span><spanclass="pre">Refresh</span><spanclass="pre">is</span><spanclass="pre">True</span></code>: The default key mixed with the applier’s dbref. This makes the buff “unique-per-player”, so you can refresh through reapplication.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">Unique</span><spanclass="pre">is</span><spanclass="pre">False,</span><spanclass="pre">Refresh</span><spanclass="pre">is</span><spanclass="pre">False</span></code>: The default key mixed with a randomized number.</p></li>
</ul>
</section>
<sectionid="get-buffs">
<h3>Get Buffs<aclass="headerlink"href="#get-buffs"title="Permalink to this headline">¶</a></h3>
<p>The handler has several getter methods which return instanced buffs. You won’t need to use these for basic functionality, but if you want to manipulate
buffs after application, they are very useful. The handler’s <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code> methods utilize some of these getters, while others are just for developer convenience.</p>
<p><codeclass="docutils literal notranslate"><spanclass="pre">get(key)</span></code> is the most basic getter. It returns a single buff instance, or <codeclass="docutils literal notranslate"><spanclass="pre">None</span></code> if the buff doesn’t exist on the handler. It is also the only getter
that returns a single buff instance, rather than a dictionary.</p>
<blockquote>
<div><p><strong>Note</strong>: The handler method <codeclass="docutils literal notranslate"><spanclass="pre">has(buff)</span></code> allows you to check if a matching key (if a string) or buff class (if a class) is present on the handler cache, without actually instantiating the buff. You should use this method for basic “is this buff present?” checks.</p>
</div></blockquote>
<p>Group getters, listed below, return a dictionary of values in the format <codeclass="docutils literal notranslate"><spanclass="pre">{buffkey:</span><spanclass="pre">instance}</span></code>. If you want to iterate over all of these buffs,
you should do so via the <codeclass="docutils literal notranslate"><spanclass="pre">dict.values()</span></code> method.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_all()</span></code> returns all buffs on this handler. You can also use the <codeclass="docutils literal notranslate"><spanclass="pre">handler.all</span></code> property.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_by_type(BuffClass)</span></code> returns buffs of the specified type.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_by_stat(stat)</span></code> returns buffs with a <codeclass="docutils literal notranslate"><spanclass="pre">Mod</span></code> object of the specified <codeclass="docutils literal notranslate"><spanclass="pre">stat</span></code> string in their <codeclass="docutils literal notranslate"><spanclass="pre">mods</span></code> list.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_by_trigger(string)</span></code> returns buffs with the specified string in their <codeclass="docutils literal notranslate"><spanclass="pre">triggers</span></code> list.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_by_source(Object)</span></code> returns buffs applied by the specified <codeclass="docutils literal notranslate"><spanclass="pre">source</span></code> object.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">get_by_cachevalue(key,</span><spanclass="pre">value)</span></code> returns buffs with the matching <codeclass="docutils literal notranslate"><spanclass="pre">key:</span><spanclass="pre">value</span></code> pair in their cache. <codeclass="docutils literal notranslate"><spanclass="pre">value</span></code> is optional.</p></li>
</ul>
<p>All group getters besides <codeclass="docutils literal notranslate"><spanclass="pre">get_all()</span></code> can “slice” an existing dictionary through the optional <codeclass="docutils literal notranslate"><spanclass="pre">to_filter</span></code> argument.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="n">dict1</span><spanclass="o">=</span><spanclass="n">handler</span><spanclass="o">.</span><spanclass="n">get_by_type</span><spanclass="p">(</span><spanclass="n">Burned</span><spanclass="p">)</span><spanclass="c1"># This finds all "Burned" buffs on the handler</span>
<spanclass="n">dict2</span><spanclass="o">=</span><spanclass="n">handler</span><spanclass="o">.</span><spanclass="n">get_by_source</span><spanclass="p">(</span><spanclass="bp">self</span><spanclass="p">,</span><spanclass="n">to_filter</span><spanclass="o">=</span><spanclass="n">dict1</span><spanclass="p">)</span><spanclass="c1"># This filters dict1 to find buffs with the matching source</span>
</pre></div>
</div>
<blockquote>
<div><p><strong>Note</strong>: Most of these getters also have an associated handler property. For example, <codeclass="docutils literal notranslate"><spanclass="pre">handler.effects</span></code> returns all buffs that can be triggered, which
is then iterated over by the <codeclass="docutils literal notranslate"><spanclass="pre">get_by_trigger</span></code> method.</p>
</div></blockquote>
</section>
<sectionid="remove-buffs">
<h3>Remove Buffs<aclass="headerlink"href="#remove-buffs"title="Permalink to this headline">¶</a></h3>
<p>There are also a number of remover methods. Generally speaking, these follow the same format as the getters.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove(key)</span></code> removes the buff with the specified key.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">clear()</span></code> removes all buffs.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove_by_type(BuffClass)</span></code> removes buffs of the specified type.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove_by_stat(stat)</span></code> removes buffs with a <codeclass="docutils literal notranslate"><spanclass="pre">Mod</span></code> object of the specified <codeclass="docutils literal notranslate"><spanclass="pre">stat</span></code> string in their <codeclass="docutils literal notranslate"><spanclass="pre">mods</span></code> list.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove_by_trigger(string)</span></code> removes buffs with the specified string in their <codeclass="docutils literal notranslate"><spanclass="pre">triggers</span></code> list.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove_by_source(Object)</span></code> removes buffs applied by the specified source</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove_by_cachevalue(key,</span><spanclass="pre">value)</span></code> removes buffs with the matching <codeclass="docutils literal notranslate"><spanclass="pre">key:</span><spanclass="pre">value</span></code> pair in their cache. <codeclass="docutils literal notranslate"><spanclass="pre">value</span></code> is optional.</p></li>
</ul>
<p>You can also remove a buff by calling the instance’s <codeclass="docutils literal notranslate"><spanclass="pre">remove</span></code> helper method. You can do this on the dictionaries returned by the
getters listed above.</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="n">to_remove</span><spanclass="o">=</span><spanclass="n">handler</span><spanclass="o">.</span><spanclass="n">get_by_trigger</span><spanclass="p">(</span><spanclass="n">trigger</span><spanclass="p">)</span><spanclass="c1"># Finds all buffs with the specified trigger</span>
<spanclass="k">for</span><spanclass="n">buff</span><spanclass="ow">in</span><spanclass="n">to_remove</span><spanclass="o">.</span><spanclass="n">values</span><spanclass="p">():</span><spanclass="c1"># Removes all buffs in the to_remove dictionary via helper methods</span>
<h3>Check Modifiers<aclass="headerlink"href="#check-modifiers"title="Permalink to this headline">¶</a></h3>
<p>Call the handler <codeclass="docutils literal notranslate"><spanclass="pre">check(value,</span><spanclass="pre">stat)</span></code> method when you want to see the modified value.
This will return the <codeclass="docutils literal notranslate"><spanclass="pre">value</span></code>, modified by any relevant buffs on the handler’s owner (identified by
the <codeclass="docutils literal notranslate"><spanclass="pre">stat</span></code> string).</p>
<p>For example, let’s say you want to modify how much damage you take. That might look something like this:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># The method we call to damage ourselves</span>
<p>This method calls the <codeclass="docutils literal notranslate"><spanclass="pre">at_pre_check</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">at_post_check</span></code> methods at the relevant points in the process. You can use to this make
buffs that are reactive to being checked; for example, removing themselves, altering their values, or interacting with the game state.</p>
<blockquote>
<div><p><strong>Note</strong>: You can also trigger relevant buffs at the same time as you check them by ensuring the optional argument <codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code> is True in the <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code> method.</p>
</div></blockquote>
<p>Modifiers are calculated additively - that is, all modifiers of the same type are added together before being applied. They are then
<h4>Multiplicative Buffs (Advanced)<aclass="headerlink"href="#multiplicative-buffs-advanced"title="Permalink to this headline">¶</a></h4>
<p>Multiply/divide modifiers in this buff system are additive by default. This means that two +50% modifiers will equal a +100% modifier. But what if you want to apply mods multiplicatively?</p>
<p>First, you should carefully consider if you truly want multiplicative modifiers. Here’s some things to consider.</p>
<ulclass="simple">
<li><p>They are unintuitive to the average user, as two +50% damage buffs equal +125% instead of +100%.</p></li>
<li><p>They lead to “power explosion”, where stacking buffs in the right way can turn characters into unstoppable forces</p></li>
</ul>
<p>Doing purely-additive multipliers allows you to better control the balance of your game. Conversely, doing multiplicative multipliers enables very fun build-crafting where smart usage of buffs and skills can turn you into a one-shot powerhouse. Each has its place.</p>
<p>The best design practice for multiplicative buffs is to divide your multipliers into “tiers”, where each tier is applied separately. You can easily do this with multiple <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code> calls.</p>
<h4>Buff Strength Priority (Advanced)<aclass="headerlink"href="#buff-strength-priority-advanced"title="Permalink to this headline">¶</a></h4>
<p>Sometimes you only want to apply the strongest modifier to a stat. This is supported by the optional <codeclass="docutils literal notranslate"><spanclass="pre">strongest</span></code> bool arg in the handler’s check method</p>
<h3>Trigger Buffs<aclass="headerlink"href="#trigger-buffs"title="Permalink to this headline">¶</a></h3>
<p>Call the handler’s <codeclass="docutils literal notranslate"><spanclass="pre">trigger(string)</span></code> method when you want an event call. This will call the <codeclass="docutils literal notranslate"><spanclass="pre">at_trigger</span></code> hook method on all buffs with the relevant trigger <codeclass="docutils literal notranslate"><spanclass="pre">string</span></code>.</p>
<p>For example, let’s say you want to trigger a buff to “detonate” when you hit your target with an attack.
<p>And then call <codeclass="docutils literal notranslate"><spanclass="pre">handler.trigger('take_damage')</span></code> in the method you use to take damage.</p>
<blockquote>
<div><p><strong>Note</strong> You could also do this through mods and <codeclass="docutils literal notranslate"><spanclass="pre">at_post_check</span></code> if you like, depending on how to want to add the damage.</p>
</div></blockquote>
</section>
<sectionid="ticking">
<h3>Ticking<aclass="headerlink"href="#ticking"title="Permalink to this headline">¶</a></h3>
<p>Ticking buffs are slightly special. They are similar to trigger buffs in that they run code, but instead of
doing so on an event trigger, they do so on a periodic tick. A common use case for a buff like this is a poison,
<p>To make a buff ticking, ensure the <codeclass="docutils literal notranslate"><spanclass="pre">tickrate</span></code> is 1 or higher, and it has code in its <codeclass="docutils literal notranslate"><spanclass="pre">at_tick</span></code>
method. Once you add it to the handler, it starts ticking!</p>
<blockquote>
<div><p><strong>Note</strong>: Ticking buffs always tick on initial application, when <codeclass="docutils literal notranslate"><spanclass="pre">initial</span></code> is <codeclass="docutils literal notranslate"><spanclass="pre">True</span></code>. If you don’t want your hook to fire at that time,
make sure to check the value of <codeclass="docutils literal notranslate"><spanclass="pre">initial</span></code> in your <codeclass="docutils literal notranslate"><spanclass="pre">at_tick</span></code> method.</p>
</div></blockquote>
</section>
<sectionid="context">
<h3>Context<aclass="headerlink"href="#context"title="Permalink to this headline">¶</a></h3>
<p>Every important handler method optionally accepts a <codeclass="docutils literal notranslate"><spanclass="pre">context</span></code> dictionary.</p>
<p>Context is an important concept for this handler. Every method which checks, triggers, or ticks a buff passes this
dictionary (default: empty) to the buff hook methods as keyword arguments (<codeclass="docutils literal notranslate"><spanclass="pre">**kwargs</span></code>). It is used for nothing else. This allows you to make those
methods “event-aware” by storing relevant data in the dictionary you feed to the method.</p>
<p>For example, let’s say you want a “thorns” buff which damages enemies that attack you. Let’s take our <codeclass="docutils literal notranslate"><spanclass="pre">take_damage</span></code> method
<p>Apply the buff, take damage, and watch the thorns buff do its work!</p>
</section>
<sectionid="viewing">
<h3>Viewing<aclass="headerlink"href="#viewing"title="Permalink to this headline">¶</a></h3>
<p>There are two helper methods on the handler that allow you to get useful buff information back.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">view</span></code>: Returns a dictionary of tuples in the format <codeclass="docutils literal notranslate"><spanclass="pre">{buffkey:</span><spanclass="pre">(buff.name,</span><spanclass="pre">buff.flavor)}</span></code>. Finds all buffs by default, but optionally accepts a dictionary of buffs to filter as well. Useful for basic buff readouts.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">view_modifiers(stat)</span></code>: Returns a nested dictionary of information on modifiers that affect the specified stat. The first layer is the modifier type (<codeclass="docutils literal notranslate"><spanclass="pre">add/mult/div</span></code>) and the second layer is the value type (<codeclass="docutils literal notranslate"><spanclass="pre">total/strongest</span></code>). Does not return the buffs that cause these modifiers, just the modifiers themselves (akin to using <codeclass="docutils literal notranslate"><spanclass="pre">handler.check</span></code> but without actually modifying a value). Useful for stat sheets.</p></li>
</ul>
<p>You can also create your own custom viewing methods through the various handler getters, which will always return the entire buff object.</p>
</section>
</section>
<sectionid="creating-new-buffs">
<h2>Creating New Buffs<aclass="headerlink"href="#creating-new-buffs"title="Permalink to this headline">¶</a></h2>
<p>Creating a new buff is very easy: extend <codeclass="docutils literal notranslate"><spanclass="pre">BaseBuff</span></code> into a new class, and fill in all the relevant buff details.
However, there are a lot of individual moving parts to a buff. Here’s a step-through of the important stuff.</p>
<sectionid="basics">
<h3>Basics<aclass="headerlink"href="#basics"title="Permalink to this headline">¶</a></h3>
<p>Regardless of any other functionality, all buffs have the following class attributes:</p>
<ulclass="simple">
<li><p>They have customizable <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">name</span></code>, and <codeclass="docutils literal notranslate"><spanclass="pre">flavor</span></code> strings.</p></li>
<li><p>They have a <codeclass="docutils literal notranslate"><spanclass="pre">duration</span></code> (float), and automatically clean-up at the end. Use -1 for infinite duration, and 0 to clean-up immediately. (default: -1)</p></li>
<li><p>They have a <codeclass="docutils literal notranslate"><spanclass="pre">tickrate</span></code> (float), and automatically tick if it is greater than 1 (default: 0)</p></li>
<li><p>They can stack, if <codeclass="docutils literal notranslate"><spanclass="pre">maxstacks</span></code> (int) is not equal to 1. If it’s 0, the buff stacks forever. (default: 1)</p></li>
<li><p>They can be <codeclass="docutils literal notranslate"><spanclass="pre">unique</span></code> (bool), which determines if they have a unique namespace or not. (default: True)</p></li>
<li><p>They can <codeclass="docutils literal notranslate"><spanclass="pre">refresh</span></code> (bool), which resets the duration when stacked or reapplied. (default: True)</p></li>
<li><p>They can be <codeclass="docutils literal notranslate"><spanclass="pre">playtime</span></code> (bool) buffs, where duration only counts down during active play. (default: False)</p></li>
</ul>
<p>Buffs also have a few useful properties:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">owner</span></code>: The object this buff is attached to</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">ticknum</span></code>: How many ticks the buff has gone through</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">timeleft</span></code>: How much time is remaining on the buff</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">ticking</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">stacking</span></code>: If this buff ticks/stacks (checks <codeclass="docutils literal notranslate"><spanclass="pre">tickrate</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">maxstacks</span></code>)</p></li>
</ul>
<sectionid="buff-cache-advanced">
<h4>Buff Cache (Advanced)<aclass="headerlink"href="#buff-cache-advanced"title="Permalink to this headline">¶</a></h4>
<p>Buffs always store some useful mutable information about themselves in the cache (what is stored on the owning object’s database attribute). A buff’s cache corresponds to <codeclass="docutils literal notranslate"><spanclass="pre">{buffkey:</span><spanclass="pre">buffcache}</span></code>, where <codeclass="docutils literal notranslate"><spanclass="pre">buffcache</span></code> is a dictionary containing <strong>at least</strong> the information below:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">ref</span></code> (class): The buff class path we use to construct the buff.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">start</span></code> (float): The timestamp of when the buff was applied.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">source</span></code> (Object): If specified; this allows you to track who or what applied the buff.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">prevtick</span></code> (float): The timestamp of the previous tick.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">duration</span></code> (float): The cached duration. This can vary from the class duration, depending on if the duration has been modified (paused, extended, shortened, etc).</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">tickrate</span></code> (float): The buff’s tick rate. Cannot go below 0. Altering the tickrate on an applied buff will not cause it to start ticking if it wasn’t ticking before. (<codeclass="docutils literal notranslate"><spanclass="pre">pause</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">unpause</span></code> to start/stop ticking on existing buffs)</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">stacks</span></code> (int): How many stacks they have.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">paused</span></code> (bool): Paused buffs do not clean up, modify values, tick, or fire any hook methods.</p></li>
</ul>
<p>Sometimes you will want to dynamically update a buff’s cache at runtime, such as changing a tickrate in a hook method, or altering a buff’s duration.
You can do so by using the interface <codeclass="docutils literal notranslate"><spanclass="pre">buff.cachekey</span></code>. As long as the attribute name matches a key in the cache dictionary, it will update the stored
cache with the new value.</p>
<p>If there is no matching key, it will do nothing. If you wish to add a new key to the cache, you must use the <codeclass="docutils literal notranslate"><spanclass="pre">buff.update_cache(dict)</span></code> method,
which will properly update the cache (including adding new keys) using the dictionary provided.</p>
<blockquote>
<div><p><strong>Example</strong>: You want to increase a buff’s duration by 30 seconds. You use <codeclass="docutils literal notranslate"><spanclass="pre">buff.duration</span><spanclass="pre">+=</span><spanclass="pre">30</span></code>. This new duration is now reflected on both the instance and the cache.</p>
</div></blockquote>
<p>The buff cache can also store arbitrary information. To do so, pass a dictionary through the handler <codeclass="docutils literal notranslate"><spanclass="pre">add</span></code> method (<codeclass="docutils literal notranslate"><spanclass="pre">handler.add(BuffClass,</span><spanclass="pre">to_cache=dict)</span></code>),
set the <codeclass="docutils literal notranslate"><spanclass="pre">cache</span></code> dictionary attribute on your buff class, or use the aforementioned <codeclass="docutils literal notranslate"><spanclass="pre">buff.update_cache(dict)</span></code> method.</p>
<blockquote>
<div><p><strong>Example</strong>: You store <codeclass="docutils literal notranslate"><spanclass="pre">damage</span></code> as a value in the buff cache and use it for your poison buff. You want to increase it over time, so you use <codeclass="docutils literal notranslate"><spanclass="pre">buff.damage</span><spanclass="pre">+=</span><spanclass="pre">1</span></code> in the tick method.</p>
</div></blockquote>
</section>
</section>
<sectionid="modifiers">
<h3>Modifiers<aclass="headerlink"href="#modifiers"title="Permalink to this headline">¶</a></h3>
<p>Mods are stored in the <codeclass="docutils literal notranslate"><spanclass="pre">mods</span></code> list attribute. Buffs which have one or more Mod objects in them can modify stats. You can use the handler method to check all
mods of a specific stat string and apply their modifications to the value; however, you are encouraged to use <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code> in a getter/setter, for easy access.</p>
<p>Mod objects consist of only four values, assigned by the constructor in this order:</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">stat</span></code>: The stat you want to modify. When <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code> is called, this string is used to find all the mods that are to be collected.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">mod</span></code>: The modifier. Defaults are <codeclass="docutils literal notranslate"><spanclass="pre">add</span></code> (addition/subtraction), <codeclass="docutils literal notranslate"><spanclass="pre">mult</span></code> (multiply), and <codeclass="docutils literal notranslate"><spanclass="pre">div</span></code> (divide). Modifiers are calculated additively (see <codeclass="docutils literal notranslate"><spanclass="pre">_calculate_mods</span></code> for more)</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">value</span></code>: How much value the modifier gives regardless of stacks</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">perstack</span></code>: How much value the modifier grants per stack, <strong>INCLUDING</strong> the first. (default: 0)</p></li>
</ul>
<p>The most basic way to add a Mod to a buff is to do so in the buff class definition, like this:</p>
<p>No mods applied to the value are permanent in any way. All calculations are done at runtime, and the mod values are never stored
anywhere except on the buff in question. In other words: you don’t need to track the origin of particular stat mods, and you will
never permanently change a stat modified by a buff. To remove the modification, simply remove the buff from the object.</p>
<blockquote>
<div><p><strong>Note</strong>: You can add your own modifier types by overloading the <codeclass="docutils literal notranslate"><spanclass="pre">_calculate_mods</span></code> method, which contains the basic modifier application logic.</p>
</div></blockquote>
<sectionid="generating-mods-advanced">
<h4>Generating Mods (Advanced)<aclass="headerlink"href="#generating-mods-advanced"title="Permalink to this headline">¶</a></h4>
<p>An advanced way to do mods is to generate them when the buff is initialized. This lets you create mods on the fly that are reactive to the game state.</p>
<h3>Triggers<aclass="headerlink"href="#triggers"title="Permalink to this headline">¶</a></h3>
<p>Buffs which have one or more strings in the <codeclass="docutils literal notranslate"><spanclass="pre">triggers</span></code> attribute can be triggered by events.</p>
<p>When the handler’s <codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code> method is called, it searches all buffs on the handler for any with a matchingtrigger,
then calls their <codeclass="docutils literal notranslate"><spanclass="pre">at_trigger</span></code> hooks. Buffs can have multiple triggers, and you can tell which trigger was used by
the <codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code> argument in the hook.</p>
<div><p><strong>Note</strong>: The buff always ticks once when applied. For this <strong>first tick only</strong>, <codeclass="docutils literal notranslate"><spanclass="pre">initial</span></code> will be True in the <codeclass="docutils literal notranslate"><spanclass="pre">at_tick</span></code> hook method. <codeclass="docutils literal notranslate"><spanclass="pre">initial</span></code> will be False on subsequent ticks.</p>
</div></blockquote>
<p>Ticks utilize a persistent delay, so they should be pickleable. As long as you are not adding new properties to your buff class, this shouldn’t be a concern.
If you <strong>are</strong> adding new properties, try to ensure they do not end up with a circular code path to their object or handler, as this will cause pickling errors.</p>
</section>
<sectionid="extras">
<h3>Extras<aclass="headerlink"href="#extras"title="Permalink to this headline">¶</a></h3>
<p>Buffs have a grab-bag of extra functionality to let you add complexity to your designs.</p>
<sectionid="conditionals">
<h4>Conditionals<aclass="headerlink"href="#conditionals"title="Permalink to this headline">¶</a></h4>
<p>You can restrict whether or not the buff will <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code>, or <codeclass="docutils literal notranslate"><spanclass="pre">tick</span></code> through defining the <codeclass="docutils literal notranslate"><spanclass="pre">conditional</span></code> hook. As long
as it returns a “truthy” value, the buff will apply itself. This is useful for making buffs dependent on game state - for
example, if you want a buff that makes the player take more damage when they are on fire:</p>
<p>Conditionals for <codeclass="docutils literal notranslate"><spanclass="pre">check</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">trigger</span></code> are checked when the buffs are gathered by the handler methods for the respective operations. <codeclass="docutils literal notranslate"><spanclass="pre">Tick</span></code>
conditionals are checked each tick.</p>
</section>
<sectionid="helper-methods">
<h4>Helper Methods<aclass="headerlink"href="#helper-methods"title="Permalink to this headline">¶</a></h4>
<p>Buff instances have a number of helper methods.</p>
<ulclass="simple">
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">remove</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">dispel</span></code>: Allows you to remove or dispel the buff. Calls <codeclass="docutils literal notranslate"><spanclass="pre">at_remove</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">at_dispel</span></code>, depending on optional arguments.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">pause</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">unpause</span></code>: Pauses and unpauses the buff. Calls <codeclass="docutils literal notranslate"><spanclass="pre">at_pause</span></code>/<codeclass="docutils literal notranslate"><spanclass="pre">at_unpause</span></code>.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">reset</span></code>: Resets the buff’s start to the current time; same as “refreshing” it.</p></li>
<li><p><codeclass="docutils literal notranslate"><spanclass="pre">alter_cache</span></code>: Updates the buff’s cache with the <codeclass="docutils literal notranslate"><spanclass="pre">{key:value}</span></code> pairs in the provided dictionary. Can overwrite default values, so be careful!</p></li>
</ul>
</section>
<sectionid="playtime-duration">
<h4>Playtime Duration<aclass="headerlink"href="#playtime-duration"title="Permalink to this headline">¶</a></h4>
<p>If your handler has <codeclass="docutils literal notranslate"><spanclass="pre">autopause</span></code> enabled, any buffs with truthy <codeclass="docutils literal notranslate"><spanclass="pre">playtime</span></code> value will automatically pause
and unpause when the object the handler is attached to is puppetted or unpuppetted. This even works with ticking buffs,
although if you have less than 1 second of tick duration remaining, it will round up to 1s.</p>
<blockquote>
<div><p><strong>Note</strong>: If you want more control over this process, you can comment out the signal subscriptions on the handler and move the autopause logic
to your object’s <codeclass="docutils literal notranslate"><spanclass="pre">at_pre/post_puppet/unpuppet</span></code> hooks.</p>
</div></blockquote>
<hrclass="docutils"/>
<p><small>This document page is generated from <codeclass="docutils literal notranslate"><spanclass="pre">evennia/contrib/rpg/buffs/README.md</span></code>. Changes to this
file will be overwritten, so edit that file rather than this one.</small></p>