Some docstring cleanup

This commit is contained in:
Griatch 2021-05-08 10:09:04 +02:00
parent 170db66d2c
commit 8ab169f70b
4 changed files with 118 additions and 82 deletions

View file

@ -121,6 +121,14 @@ local:
@echo "Documentation built (single version)." @echo "Documentation built (single version)."
@echo "To see result, open evennia/docs/build/html/index.html in a browser." @echo "To see result, open evennia/docs/build/html/index.html in a browser."
# build only that which updated since last run (no clean or index-creation)
localupdate:
make _check-env
make _html-build
@echo ""
@echo "Documentation built (single version, only updates, no auto-index)."
@echo "To see result, open evennia/docs/build/html/index.html in a browser."
# note that this should be done for each relevant multiversion branch. # note that this should be done for each relevant multiversion branch.
mv-index: mv-index:
make _multiversion-autodoc-index make _multiversion-autodoc-index

View file

@ -38,7 +38,7 @@ than, the doc-strings of each component in the [API](../Evennia-API).
- [MonitorHandler](./MonitorHandler) - [MonitorHandler](./MonitorHandler)
- [TickerHandler](./TickerHandler) - [TickerHandler](./TickerHandler)
- [Lock system](./Locks) - [Lock system](./Locks)
- [FuncParser](FuncParser) - [FuncParser](./FuncParser)
## Server and network ## Server and network

View file

@ -14,31 +14,31 @@ a server reload/reboot).
## Adding Traits to a typeclass ## Adding Traits to a typeclass
To access and manipulate traits on an object, its Typeclass needs to have a To access and manipulate traits on an entity, its Typeclass needs to have a
`TraitHandler` assigned it. Usually, the handler is made available as `.traits` `TraitHandler` assigned it. Usually, the handler is made available as `.traits`
(in the same way as `.tags` or `.attributes`). (in the same way as `.tags` or `.attributes`). It's recommended to do this
using Evennia's `lazy_property` (which basically just means it's not
initialized until it's actually accessed).
Here's an example for adding the TraitHandler to the base Object class: Here's an example for adding the TraitHandler to the base Object class:
```python ```python
# mygame/typeclasses/objects.py # mygame/typeclasses/objects.py
from evennia import DefaultObject from evennia import DefaultObject
from evennia.utils import lazy_property from evennia.utils import lazy_property
from evennia.contrib.traits import TraitHandler from evennia.contrib.traits import TraitHandler
# ... # ...
class Object(DefaultObject): class Object(DefaultObject):
... ...
@lazy_property @lazy_property
def traits(self): def traits(self):
# this adds the handler as .traits # this adds the handler as .traits
return TraitHandler(self) return TraitHandler(self)
``` ```
After a reload you can now try adding some example traits:
## Using traits ## Using traits
@ -48,6 +48,7 @@ in Evennia).
```python ```python
# this is an example using the "static" trait, described below # this is an example using the "static" trait, described below
>>> obj.traits.add("hunting", "Hunting Skill", trait_type="static", base=4) >>> obj.traits.add("hunting", "Hunting Skill", trait_type="static", base=4)
>>> obj.traits.hunting.value >>> obj.traits.hunting.value
4 4
@ -130,17 +131,19 @@ that varies slowly or not at all, and which may be modified in-place.
``` ```
### Counter ### Counter
::
min/unset base base+mod max/unset min/unset base base+mod max/unset
|--------------|--------|---------X--------X------------| |--------------|--------|---------X--------X------------|
current value current value
= current = current
+ mod + mod
A counter describes a value that can move from a base. The `current` property A counter describes a value that can move from a base. The `.current` property
is the thing usually modified. It starts at the `base`. One can also add a modifier, is the thing usually modified. It starts at the `.base`. One can also add a
which will both be added to the base and to current (forming .value). modifier, which will both be added to the base and to current (forming
The min/max of the range are optional, a boundary set to None will remove it. `.value`). The min/max of the range are optional, a boundary set to None will
remove it. A suggested use for a Counter Trait would be to track skill values.
```python ```python
>>> obj.traits.add("hunting", "Hunting Skill", trait_type="counter", >>> obj.traits.add("hunting", "Hunting Skill", trait_type="counter",
@ -160,10 +163,15 @@ The min/max of the range are optional, a boundary set to None will remove it.
Counters have some extra properties: Counters have some extra properties:
`descs` is a dict {upper_bound:text_description}. This allows for easily #### .descs
The `descs` property is a dict {upper_bound:text_description}. This allows for easily
storing a more human-friendly description of the current value in the storing a more human-friendly description of the current value in the
interval. Here is an example for skill values between 0 and 10: interval. Here is an example for skill values between 0 and 10:
::
{0: "unskilled", 1: "neophyte", 5: "trained", 7: "expert", 9: "master"} {0: "unskilled", 1: "neophyte", 5: "trained", 7: "expert", 9: "master"}
The keys must be supplied from smallest to largest. Any values below the lowest and above the The keys must be supplied from smallest to largest. Any values below the lowest and above the
highest description will be considered to be included in the closest description slot. highest description will be considered to be included in the closest description slot.
By calling `.desc()` on the Counter, will you get the text matching the current `value` By calling `.desc()` on the Counter, will you get the text matching the current `value`
@ -190,11 +198,11 @@ value.
The `rate` property defaults to 0. If set to a value different from 0, it The `rate` property defaults to 0. If set to a value different from 0, it
allows the trait to change value dynamically. This could be used for example allows the trait to change value dynamically. This could be used for example
for an attribute that was temporarily lowered but will gradually (or abruptly) for an attribute that was temporarily lowered but will gradually (or abruptly)
recover after a certain time. The rate is given as change of the `current` recover after a certain time. The rate is given as change of the current
per-second, and the .value will still be restrained by min/max boundaries, if `.value` per-second, and this will still be restrained by min/max boundaries,
those are set. if those are set.
It is also possible to set a ".ratetarget", for the auto-change to stop at It is also possible to set a `.ratetarget`, for the auto-change to stop at
(rather than at the min/max boundaries). This allows the value to return to (rather than at the min/max boundaries). This allows the value to return to
a previous value. a previous value.
@ -220,35 +228,41 @@ a previous value.
>>> obj.traits.hunting.rate = 0 # disable auto-change >>> obj.traits.hunting.rate = 0 # disable auto-change
``` ```
Note that if rate is a non-integer, the resulting .value (at least until it Note that if `.rate` is a non-integer, the resulting `.value` (at least until it
reaches the boundary) will likely also come out a float. If you expect an reaches a boundary or rate-target) will also come out a float (so you can get a
integer, you must run run int() on the result yourself. very exact value at the current time). If you expect an integer, you must run
`int()` (or something like `round()`) on the result yourself.
#### .percentage() #### .percent()
If both min and max are defined, the `.percentage()` method of the trait will If both min and max are defined, the `.percent()` method of the trait will
return the value as a percentage. return the value as a percentage.
```python ```python
>>> obj.traits.hunting.percentage() >>> obj.traits.hunting.percent()
"71.0%" "71.0%"
>>> obj.traits.hunting.percent(formatting=None)
71.0
``` ```
### Gauge ### Gauge
This emulates a [fuel-] gauge that empties from a base+mod value. This emulates a [fuel-] gauge that empties from a base+mod value.
::
min/0 max=base+mod min/0 max=base+mod
|-----------------------X---------------------------| |-----------------------X---------------------------|
value value
= current = current
The 'current' value will start from a full gauge. The .max property is The `.current` value will start from a full gauge. The .max property is
read-only and is set by .base + .mod. So contrary to a Counter, the modifier read-only and is set by `.base` + `.mod`. So contrary to a `Counter`, the
only applies to the max value of the gauge and not the current value. The `.mod` modifier only applies to the max value of the gauge and not the current
minimum bound defaults to 0. This trait is useful for showing resources that value. The minimum bound defaults to 0 if not set explicitly.
can deplete, like health, stamina and the like.
This trait is useful for showing commonly depletable resources like health,
stamina and the like.
```python ```python
>>> obj.traits.add("hp", "Health", trait_type="gauge", base=100) >>> obj.traits.add("hp", "Health", trait_type="gauge", base=100)
@ -263,20 +277,24 @@ can deplete, like health, stamina and the like.
``` ```
Same as Counters, Gauges can also have `descs` to describe the interval and can also The Gauge trait is subclass of the Counter, so you have access to the same
have `rate` and `ratetarget` to auto-update the value. The rate is particularly useful methods and properties where they make sense. So gauges can also have a
for gauges, for everything from poison slowly draining your health, to resting gradually `.descs` dict to describe the intervals in text, and can use `.percent()` to
increasing it. You can also use the `.percentage()` function to show the current value get how filled it is as a percentage etc.
as a percentage.
The `.rate` is particularly relevant for gauges - useful for everything
from poison slowly draining your health, to resting gradually increasing it.
### Trait ### Trait
A single value of any type. A single value of any type.
This is the 'base' Trait, meant to inherit from if you want to make your own This is the 'base' Trait, meant to inherit from if you want to invent
trait-types (see below). Its .value can be anything (that can be stored in an Attribute) trait-types from scratch (most of the time you'll probably inherit from some of
and if it's a integer/float you can do arithmetic with it, but otherwise it the more advanced trait-type classes though). A `Trait`s `.value` can be
acts just like a glorified Attribute. anything (that can be stored in an Attribute) and if it's a integer/float you
can do arithmetic with it, but otherwise it acts just like a glorified
Attribute.
```python ```python
@ -291,38 +309,45 @@ acts just like a glorified Attribute.
## Expanding with your own Traits ## Expanding with your own Traits
A Trait is a class inhering from `evennia.contrib.traits.Trait` (or A Trait is a class inhering from `evennia.contrib.traits.Trait` (or from one of
from one of the existing Trait classes). the existing Trait classes).
```python ```python
# in a file, say, 'mygame/world/traits.py' # in a file, say, 'mygame/world/traits.py'
from evennia.contrib.traits import Trait from evennia.contrib.traits import StaticTrait
class RageTrait(Trait): class RageTrait(StaticTrait):
trait_type = "rage" trait_type = "rage"
default_keys = { default_keys = {
"rage": 0 "rage": 0
} }
def berserk(self):
self.mod = 100
def sedate(self):
self.mod = 0
``` ```
Above is an example custom-trait-class "rage" that stores a property "rage" on Above is an example custom-trait-class "rage" that stores a property "rage" on
itself, with a default value of 0. This has all the itself, with a default value of 0. This has all the functionality of a Trait -
functionality of a Trait - for example, if you do del on the `rage` property, it will be for example, if you do del on the `rage` property, it will be set back to its
set back to its default (0). If you wanted to customize what it does, you default (0). Above we also added some helper methods.
just add `rage` property get/setters/deleters on the class.
To add your custom RageTrait to Evennia, add the following to your settings file To add your custom RageTrait to Evennia, add the following to your settings file
(assuming your class is in mygame/world/traits.py): (assuming your class is in mygame/world/traits.py):
::
TRAIT_CLASS_PATHS = ["world.traits.RageTrait"] TRAIT_CLASS_PATHS = ["world.traits.RageTrait"]
Reload the server and you should now be able to use your trait: Reload the server and you should now be able to use your trait:
```python ```python
>>> obj.traits.add("mood", "A dark mood", rage=30) >>> obj.traits.add("mood", "A dark mood", rage=30, trait_type='rage')
>>> obj.traits.mood.rage >>> obj.traits.mood.rage
30 30

View file

@ -1710,36 +1710,39 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
Args: Args:
prompt (str): The yes/no question to ask. This takes an optional formatting prompt (str): The yes/no question to ask. This takes an optional formatting
marker `{suffix}` which will be filled with 'Y/N', [Y]/N or Y/[N] marker `{options}` which will be filled with 'Y/N', '[Y]/N' or
depending on the setting of `default`. If `allow_abort`, then the 'Y/[N]' depending on the setting of `default`. If `allow_abort` is set,
`A(bort)` will also be available. then the 'A(bort)' option will also be available.
yes_action (callable or str): If a callable, this will be called yes_action (callable or str): If a callable, this will be called
with `(caller, *args, **kwargs) when the yes-choice is made. with `(caller, *args, **kwargs)` when the Yes-choice is made.
If a string, this string will be echoed back to the caller. If a string, this string will be echoed back to the caller.
no_action (callable or str): If a callable, this will be called no_action (callable or str): If a callable, this will be called
with `(caller, *args, **kwargs)` when the no-choice is made. with `(caller, *args, **kwargs)` when the No-choice is made.
If a string, this string will be echoed back to the caller. If a string, this string will be echoed back to the caller.
default (str optional): One of "N", "Y", "A" or None for no default. default (str optional): This is what the user will get if they just press the
If "A" is given, `allow_abort` is assumed set. The user can choose return key without giving any input. One of 'N', 'Y', 'A' or 'None'
the default option just by pressing return. for no default. If 'A' is given, `allow_abort` is auto-set.
allow_abort (bool, optional): If set, the Q(uit) option is available, allow_abort (bool, optional): If set, the 'A(bort)' option is available
which is neither yes or no. (a third option meaning neither yes or no but just exits the prompt).
session (Session, optional): This allows to specify the session (Session, optional): This allows to specify the
session to send the prompt to. It's usually only needed if `caller` session to send the prompt to. It's usually only needed if `caller`
is an Account in multisession modes greater than 2. The session is is an Account in multisession modes greater than 2. The session is
then updated by the command and is available (for example in then updated by the command and is available (for example in
callbacks) through `caller.ndb._yes_no_question.session`. callbacks) through `caller.ndb._yes_no_question.session`.
*args, **kwargs: These are passed into the callables, if any. *args, **kwargs: These are passed into the callables.
Raises: Raises:
RuntimeError: If default and allow_abort clashes. RuntimeError, FooError: If default and allow_abort clashes.
Example: Example:
::
ask_yes_no(caller, "Are you happy {suffix}?", # just returning strings
"you answered yes", "you answered no") ask_yes_no(caller, "Are you happy {options}?",
ask_yes_no(caller, "Are you sad {suffix}?", "you answered yes", "you answered no")
_callable_yes, _callable_no, allow_abort=True) # trigger callables
ask_yes_no(caller, "Are you sad {options}?",
_callable_yes, _callable_no, allow_abort=True)
""" """
def _callable_yes_txt(caller, *args, **kwargs): def _callable_yes_txt(caller, *args, **kwargs):
@ -1760,20 +1763,20 @@ def ask_yes_no(caller, prompt, yes_action, no_action, default=None,
kwargs['no_txt'] = str(no_action) kwargs['no_txt'] = str(no_action)
no_action = _callable_no_txt no_action = _callable_no_txt
# prepare the prompt with suffix # prepare the prompt with options
suffix = "Y/N" options = "Y/N"
abort_txt = "/Abort" if allow_abort else "" abort_txt = "/Abort" if allow_abort else ""
if default: if default:
default = default.lower() default = default.lower()
if default == "y": if default == "y":
suffix = "[Y]/N" options = "[Y]/N"
elif default == "n": elif default == "n":
suffix = "Y/[N]" options = "Y/[N]"
elif default == "a": elif default == "a":
allow_abort = True allow_abort = True
abort_txt = "/[A]bort" abort_txt = "/[A]bort"
suffix += abort_txt options += abort_txt
prompt = prompt.format(suffix=suffix) prompt = prompt.format(options=options)
caller.ndb._yes_no_question = _Prompt() caller.ndb._yes_no_question = _Prompt()
caller.ndb._yes_no_question.session = session caller.ndb._yes_no_question.session = session