Update prototype example module
This commit is contained in:
parent
b086e95e19
commit
c051d15f5c
3 changed files with 104 additions and 52 deletions
|
|
@ -2,40 +2,56 @@
|
||||||
Prototypes
|
Prototypes
|
||||||
|
|
||||||
A prototype is a simple way to create individualized instances of a
|
A prototype is a simple way to create individualized instances of a
|
||||||
given `Typeclass`. For example, you might have a Sword typeclass that
|
given typeclass. It is dictionary with specific key names.
|
||||||
implements everything a Sword would need to do. The only difference
|
|
||||||
between different individual Swords would be their key, description
|
|
||||||
and some Attributes. The Prototype system allows to create a range of
|
|
||||||
such Swords with only minor variations. Prototypes can also inherit
|
|
||||||
and combine together to form entire hierarchies (such as giving all
|
|
||||||
Sabres and all Broadswords some common properties). Note that bigger
|
|
||||||
variations, such as custom commands or functionality belong in a
|
|
||||||
hierarchy of typeclasses instead.
|
|
||||||
|
|
||||||
Example prototypes are read by the `@spawn` command but is also easily
|
For example, you might have a Sword typeclass that implements everything a
|
||||||
available to use from code via `evennia.spawn` or `evennia.utils.spawner`.
|
Sword would need to do. The only difference between different individual Swords
|
||||||
Each prototype should be a dictionary. Use the same name as the
|
would be their key, description and some Attributes. The Prototype system
|
||||||
variable to refer to other prototypes.
|
allows to create a range of such Swords with only minor variations. Prototypes
|
||||||
|
can also inherit and combine together to form entire hierarchies (such as
|
||||||
|
giving all Sabres and all Broadswords some common properties). Note that bigger
|
||||||
|
variations, such as custom commands or functionality belong in a hierarchy of
|
||||||
|
typeclasses instead.
|
||||||
|
|
||||||
|
A prototype can either be a dictionary placed into a global variable in a
|
||||||
|
python module (a 'module-prototype') or stored in the database as a dict on a
|
||||||
|
special Script (a db-prototype). The former can be created just by adding dicts
|
||||||
|
to modules Evennia looks at for prototypes, the latter is easiest created
|
||||||
|
in-game via the `olc` command/menu.
|
||||||
|
|
||||||
|
Prototypes are read and used to create new objects with the `spawn` command
|
||||||
|
or directly via `evennia.spawn` or the full path `evennia.prototypes.spawner.spawn`.
|
||||||
|
|
||||||
|
A prototype dictionary have the following keywords:
|
||||||
|
|
||||||
Possible keywords are:
|
Possible keywords are:
|
||||||
prototype_parent - string pointing to parent prototype of this structure.
|
- `prototype_key` - the name of the prototype. This is required for db-prototypes,
|
||||||
key - string, the main object identifier.
|
for module-prototypes, the global variable name of the dict is used instead
|
||||||
typeclass - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`.
|
- `prototype_parent` - string pointing to parent prototype if any. Prototype inherits
|
||||||
location - this should be a valid object or #dbref.
|
in a similar way as classes, with children overriding values in their partents.
|
||||||
home - valid object or #dbref.
|
- `key` - string, the main object identifier.
|
||||||
destination - only valid for exits (object or dbref).
|
- `typeclass` - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`.
|
||||||
|
- `location` - this should be a valid object or #dbref.
|
||||||
|
- `home` - valid object or #dbref.
|
||||||
|
- `destination` - only valid for exits (object or #dbref).
|
||||||
|
- `permissions` - string or list of permission strings.
|
||||||
|
- `locks` - a lock-string to use for the spawned object.
|
||||||
|
- `aliases` - string or list of strings.
|
||||||
|
- `attrs` - Attributes, expressed as a list of tuples on the form `(attrname, value)`,
|
||||||
|
`(attrname, value, category)`, or `(attrname, value, category, locks)`. If using one
|
||||||
|
of the shorter forms, defaults are used for the rest.
|
||||||
|
- `tags` - Tags, as a list of tuples `(tag,)`, `(tag, category)` or `(tag, category, data)`.
|
||||||
|
- Any other keywords are interpreted as Attributes with no category or lock.
|
||||||
|
These will internally be added to `attrs` (eqivalent to `(attrname, value)`.
|
||||||
|
|
||||||
permissions - string or list of permission strings.
|
See the `spawn` command and `evennia.prototypes.spawner.spawn` for more info.
|
||||||
locks - a lock-string.
|
|
||||||
aliases - string or list of strings.
|
|
||||||
|
|
||||||
ndb_<name> - value of a nattribute (the "ndb_" part is ignored).
|
|
||||||
any other keywords are interpreted as Attributes and their values.
|
|
||||||
|
|
||||||
See the `@spawn` command and `evennia.utils.spawner` for more info.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
## example of module-based prototypes using
|
||||||
|
## the variable name as `prototype_key` and
|
||||||
|
## simple Attributes
|
||||||
|
|
||||||
# from random import randint
|
# from random import randint
|
||||||
#
|
#
|
||||||
# GOBLIN = {
|
# GOBLIN = {
|
||||||
|
|
@ -43,7 +59,8 @@ See the `@spawn` command and `evennia.utils.spawner` for more info.
|
||||||
# "health": lambda: randint(20,30),
|
# "health": lambda: randint(20,30),
|
||||||
# "resists": ["cold", "poison"],
|
# "resists": ["cold", "poison"],
|
||||||
# "attacks": ["fists"],
|
# "attacks": ["fists"],
|
||||||
# "weaknesses": ["fire", "light"]
|
# "weaknesses": ["fire", "light"],
|
||||||
|
# "tags": = [("greenskin", "monster"), ("humanoid", "monster")]
|
||||||
# }
|
# }
|
||||||
#
|
#
|
||||||
# GOBLIN_WIZARD = {
|
# GOBLIN_WIZARD = {
|
||||||
|
|
|
||||||
|
|
@ -592,7 +592,7 @@ def validate_prototype(
|
||||||
protparent = protparents.get(protstring)
|
protparent = protparents.get(protstring)
|
||||||
if not protparent:
|
if not protparent:
|
||||||
_flags["errors"].append(
|
_flags["errors"].append(
|
||||||
"Prototype {}'s prototype_parent '{}' was not found.".format((protkey, protstring))
|
"Prototype {}'s prototype_parent '{}' was not found.".format(protkey, protstring)
|
||||||
)
|
)
|
||||||
if id(prototype) in _flags["visited"]:
|
if id(prototype) in _flags["visited"]:
|
||||||
_flags["errors"].append(
|
_flags["errors"].append(
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ caller.msg() construct every time the page is updated.
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.models.query import QuerySet
|
from django.db.models.query import QuerySet
|
||||||
|
from django.core.paginator import Paginator
|
||||||
from evennia import Command, CmdSet
|
from evennia import Command, CmdSet
|
||||||
from evennia.commands import cmdhandler
|
from evennia.commands import cmdhandler
|
||||||
from evennia.utils.utils import make_iter, inherits_from, justify
|
from evennia.utils.utils import make_iter, inherits_from, justify
|
||||||
|
|
@ -131,7 +132,7 @@ class EvMore(object):
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
caller,
|
caller,
|
||||||
text,
|
inp,
|
||||||
always_page=False,
|
always_page=False,
|
||||||
session=None,
|
session=None,
|
||||||
justify=False,
|
justify=False,
|
||||||
|
|
@ -143,28 +144,28 @@ class EvMore(object):
|
||||||
):
|
):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Initialization of the text handler.
|
Initialization of the inp handler.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
caller (Object or Account): Entity reading the text.
|
caller (Object or Account): Entity reading the text.
|
||||||
text (str, EvTable or iterator): The text or data to put under paging.
|
inp (str, EvTable, Paginator or iterator): The text or data to put under paging.
|
||||||
- If a string, paginage normally. If this text contains
|
- If a string, paginage normally. If this text contains
|
||||||
one or more `\f` format symbol, automatic pagination and justification
|
one or more `\f` format symbol, automatic pagination and justification
|
||||||
are force-disabled and page-breaks will only happen after each `\f`.
|
are force-disabled and page-breaks will only happen after each `\f`.
|
||||||
- If `EvTable`, the EvTable will be paginated with the same
|
- If `EvTable`, the EvTable will be paginated with the same
|
||||||
setting on each page if it is too long. The table
|
setting on each page if it is too long. The table
|
||||||
decorations will be considered in the size of the page.
|
decorations will be considered in the size of the page.
|
||||||
- Otherwise `text` is converted to an iterator, where each step is
|
- Otherwise `inp` is converted to an iterator, where each step is
|
||||||
expected to be a line in the final display. Each line
|
expected to be a line in the final display. Each line
|
||||||
will be run through `iter_callable`.
|
will be run through `iter_callable`.
|
||||||
always_page (bool, optional): If `False`, the
|
always_page (bool, optional): If `False`, the
|
||||||
pager will only kick in if `text` is too big
|
pager will only kick in if `inp` is too big
|
||||||
to fit the screen.
|
to fit the screen.
|
||||||
session (Session, optional): If given, this session will be used
|
session (Session, optional): If given, this session will be used
|
||||||
to determine the screen width and will receive all output.
|
to determine the screen width and will receive all output.
|
||||||
justify (bool, optional): If set, auto-justify long lines. This must be turned
|
justify (bool, optional): If set, auto-justify long lines. This must be turned
|
||||||
off for fixed-width or formatted output, like tables. It's force-disabled
|
off for fixed-width or formatted output, like tables. It's force-disabled
|
||||||
if `text` is an EvTable.
|
if `inp` is an EvTable.
|
||||||
justify_kwargs (dict, optional): Keywords for the justifiy function. Used only
|
justify_kwargs (dict, optional): Keywords for the justifiy function. Used only
|
||||||
if `justify` is True. If this is not set, default arguments will be used.
|
if `justify` is True. If this is not set, default arguments will be used.
|
||||||
exit_on_lastpage (bool, optional): If reaching the last page without the
|
exit_on_lastpage (bool, optional): If reaching the last page without the
|
||||||
|
|
@ -230,31 +231,51 @@ class EvMore(object):
|
||||||
# always limit number of chars to 10 000 per page
|
# always limit number of chars to 10 000 per page
|
||||||
self.height = min(10000 // max(1, self.width), height)
|
self.height = min(10000 // max(1, self.width), height)
|
||||||
|
|
||||||
if inherits_from(text, "evennia.utils.evtable.EvTable"):
|
# does initial parsing of input
|
||||||
# an EvTable
|
self.parse_input(inp)
|
||||||
self.init_evtable(text)
|
|
||||||
elif isinstance(text, QuerySet):
|
|
||||||
# a queryset
|
|
||||||
self.init_queryset(text)
|
|
||||||
elif not isinstance(text, str):
|
|
||||||
# anything else not a str
|
|
||||||
self.init_iterable(text)
|
|
||||||
elif "\f" in text:
|
|
||||||
# string with \f line-break markers in it
|
|
||||||
self.init_f_str(text)
|
|
||||||
else:
|
|
||||||
# a string
|
|
||||||
self.init_str(text)
|
|
||||||
|
|
||||||
# kick things into gear
|
# kick things into gear
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
# page formatter
|
# Hooks for customizing input handling and formatting (use if overriding this class)
|
||||||
|
|
||||||
|
def parse_input(self, inp):
|
||||||
|
"""
|
||||||
|
Parse the input to figure out the size of the data, how many pages it
|
||||||
|
consist of and pick the correct paginator mechanism. Override this if
|
||||||
|
you want to support a new type of input.
|
||||||
|
|
||||||
|
Each initializer should set self._paginator and optionally self._page_formatter
|
||||||
|
for properly handling the input data.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if inherits_from(inp, "evennia.utils.evtable.EvTable"):
|
||||||
|
# an EvTable
|
||||||
|
self.init_evtable(inp)
|
||||||
|
elif isinstance(inp, QuerySet):
|
||||||
|
# a queryset
|
||||||
|
self.init_queryset(inp)
|
||||||
|
elif isinstance(inp, Paginator):
|
||||||
|
self.init_django_paginator(inp)
|
||||||
|
elif not isinstance(inp, str):
|
||||||
|
# anything else not a str
|
||||||
|
self.init_iterable(inp)
|
||||||
|
elif "\f" in inp:
|
||||||
|
# string with \f line-break markers in it
|
||||||
|
self.init_f_str(inp)
|
||||||
|
else:
|
||||||
|
# a string
|
||||||
|
self.init_str(inp)
|
||||||
|
|
||||||
def format_page(self, page):
|
def format_page(self, page):
|
||||||
"""
|
"""
|
||||||
Page formatter. Uses the page_formatter callable by default.
|
Page formatter. Uses the page_formatter callable by default.
|
||||||
This allows to easier override the class if needed.
|
This allows to easier override the class if needed.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
page (any): A piece of data representing one page to display. This must
|
||||||
|
be poss
|
||||||
|
Returns:
|
||||||
"""
|
"""
|
||||||
return self._page_formatter(page)
|
return self._page_formatter(page)
|
||||||
|
|
||||||
|
|
@ -269,7 +290,13 @@ class EvMore(object):
|
||||||
Paginate by slice. This is done with an eye on memory efficiency (usually for
|
Paginate by slice. This is done with an eye on memory efficiency (usually for
|
||||||
querysets); to avoid fetching all objects at the same time.
|
querysets); to avoid fetching all objects at the same time.
|
||||||
"""
|
"""
|
||||||
return self._data[pageno * self.height : pageno * self.height + self.height]
|
return self._data[pageno * self.height: pageno * self.height + self.height]
|
||||||
|
|
||||||
|
def paginator_django(self, pageno):
|
||||||
|
"""
|
||||||
|
Paginate using the django queryset Paginator API. Note that his is indexed from 1.
|
||||||
|
"""
|
||||||
|
return self._data.page(pageno + 1)
|
||||||
|
|
||||||
# inits for different input types
|
# inits for different input types
|
||||||
|
|
||||||
|
|
@ -292,6 +319,14 @@ class EvMore(object):
|
||||||
self._data = qs
|
self._data = qs
|
||||||
self._paginator = self.paginator_slice
|
self._paginator = self.paginator_slice
|
||||||
|
|
||||||
|
def init_django_paginator(self, pages):
|
||||||
|
"""
|
||||||
|
The input is a django Paginator object.
|
||||||
|
"""
|
||||||
|
self._npages = pages.num_pages
|
||||||
|
self._data = pages
|
||||||
|
self._paginator = self.paginator_django
|
||||||
|
|
||||||
def init_iterable(self, inp):
|
def init_iterable(self, inp):
|
||||||
"""The input is something other than a string - convert to iterable of strings"""
|
"""The input is something other than a string - convert to iterable of strings"""
|
||||||
inp = make_iter(inp)
|
inp = make_iter(inp)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue