mirror of
https://github.com/evennia/evennia.git
synced 2026-04-06 16:44:08 +02:00
Made the spawner more streamlined, and allowed the @spawn command to access prototypes in a file specified by the optional PROTOTYPE_MODULES setting.
This commit is contained in:
parent
6eafe65076
commit
221d56fecd
4 changed files with 137 additions and 44 deletions
56
game/gamesrc/world/examples/prototypes.py
Normal file
56
game/gamesrc/world/examples/prototypes.py
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
"""
|
||||
Example prototypes read by the @spawn command but is also easily
|
||||
available to use from code. Each prototype should be a dictionary. Use
|
||||
the same name as the variable to refer to other prototypes.
|
||||
|
||||
Possible keywords are:
|
||||
prototype - string pointing to parent prototype of this structure
|
||||
key - string, the main object identifier
|
||||
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
|
||||
aliases - string or list of strings
|
||||
|
||||
ndb_<name> - value of a nattribute (ndb_ is stripped)
|
||||
any other keywords are interpreted as Attributes and their values.
|
||||
|
||||
See the @spawn command and src.utils.spawner for more info.
|
||||
|
||||
"""
|
||||
|
||||
from random import randint
|
||||
|
||||
NOBODY = {}
|
||||
|
||||
GOBLIN = {
|
||||
"key": "goblin grunt",
|
||||
"health": lambda: randint(20,30),
|
||||
"resists": ["cold", "poison"],
|
||||
"attacks": ["fists"],
|
||||
"weaknesses": ["fire", "light"]
|
||||
}
|
||||
|
||||
GOBLIN_WIZARD = {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin wizard",
|
||||
"spells": ["fire ball", "lighting bolt"]
|
||||
}
|
||||
|
||||
GOBLIN_ARCHER = {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin archer",
|
||||
"attacks": ["short bow"]
|
||||
}
|
||||
|
||||
ARCHWIZARD = {
|
||||
"attacks": ["archwizard staff"],
|
||||
}
|
||||
|
||||
GOBLIN_ARCHWIZARD = {
|
||||
"key": "goblin archwizard",
|
||||
"prototype" : ("GOBLIN_WIZARD", "ARCHWIZARD")
|
||||
}
|
||||
|
|
@ -19,7 +19,7 @@ __all__ = ("ObjManipCommand", "CmdSetObjAlias", "CmdCopy",
|
|||
"CmdUnLink", "CmdSetHome", "CmdListCmdSets", "CmdName",
|
||||
"CmdOpen", "CmdSetAttribute", "CmdTypeclass", "CmdWipe",
|
||||
"CmdLock", "CmdExamine", "CmdFind", "CmdTeleport",
|
||||
"CmdScript", "CmdTag")
|
||||
"CmdScript", "CmdTag", "CmdSpawn")
|
||||
|
||||
try:
|
||||
# used by @set
|
||||
|
|
@ -30,7 +30,7 @@ except ImportError:
|
|||
|
||||
# used by @find
|
||||
CHAR_TYPECLASS = settings.BASE_CHARACTER_TYPECLASS
|
||||
|
||||
_PROTOTYPE_PARENTS = None
|
||||
|
||||
class ObjManipCommand(MuxCommand):
|
||||
"""
|
||||
|
|
@ -2244,17 +2244,33 @@ class CmdTag(MuxCommand):
|
|||
string = "No tags attached to %s." % obj
|
||||
self.caller.msg(string)
|
||||
|
||||
#
|
||||
# To use the prototypes with the @spawn function, copy
|
||||
# game/gamesrc/world/examples/prototypes.py up one level
|
||||
# to game/gamesrc/world. Then add to game/settings.py the
|
||||
# line
|
||||
# PROTOTYPE_MODULES = ["game.gamesrc.commands.prototypes"]
|
||||
# Reload the server and the prototypes should be available.
|
||||
#
|
||||
|
||||
class CmdSpawn(MuxCommand):
|
||||
"""
|
||||
spawn objects from prototype
|
||||
|
||||
Usage:
|
||||
@spawn {prototype dictionary}
|
||||
@spawn[/switches] {prototype dictionary}
|
||||
|
||||
Switches:
|
||||
noloc - allow location to None. Otherwise, location will default to
|
||||
caller's current location
|
||||
parents - show all available prototype parents
|
||||
|
||||
Example:
|
||||
@spawn {"key":"goblin", "typeclass":"monster.Monster", "location":"#2"}
|
||||
|
||||
Dictionary keys:
|
||||
{wprototype {n - name of parent prototype to use. Can be a list for
|
||||
multiple inheritance (inherits left to right)
|
||||
{wkey {n - string, the main object identifier
|
||||
{wtypeclass {n - string, if not set, will use settings.BASE_OBJECT_TYPECLASS
|
||||
{wlocation {n - this should be a valid object or #dbref
|
||||
|
|
@ -2266,7 +2282,8 @@ class CmdSpawn(MuxCommand):
|
|||
{wndb_{n<name> - value of a nattribute (ndb_ is stripped)
|
||||
any other keywords are interpreted as Attributes and their values.
|
||||
|
||||
This command can't access prototype inheritance.
|
||||
The parent prototypes are taken as dictionaries defined globally in
|
||||
the settings.PROTOTYPE_MODULES.
|
||||
"""
|
||||
|
||||
key = "@spawn"
|
||||
|
|
@ -2274,9 +2291,22 @@ class CmdSpawn(MuxCommand):
|
|||
help_category = "Building"
|
||||
|
||||
def func(self):
|
||||
"Implements the spawn"
|
||||
"Implements the spawner"
|
||||
|
||||
global _PROTOTYPE_PARENTS
|
||||
if _PROTOTYPE_PARENTS is None:
|
||||
if hasattr(settings, "PROTOTYPE_MODULES"):
|
||||
# read prototype parents from setting
|
||||
_PROTOTYPE_PARENTS = {}
|
||||
for prototype_module in utils.make_iter(settings.PROTOTYPE_MODULES):
|
||||
_PROTOTYPE_PARENTS.update(dict((key, val)
|
||||
for key, val in utils.all_from_module(prototype_module).items() if isinstance(val, dict)))
|
||||
|
||||
if not self.args:
|
||||
self.caller.msg("Usage: @spawn {key:value, key, value, ...}")
|
||||
string = "Usage: @spawn {key:value, key, value, ...}\n" \
|
||||
"Available prototypes: %s"
|
||||
self.caller.msg(string % ", ".join(_PROTOTYPE_PARENTS.keys())
|
||||
if _PROTOTYPE_PARENTS else None)
|
||||
return
|
||||
from src.utils.spawner import spawn
|
||||
|
||||
|
|
@ -2297,7 +2327,10 @@ class CmdSpawn(MuxCommand):
|
|||
self.caller.msg("The prototype must be a Python dictionary.")
|
||||
return
|
||||
|
||||
for obj in spawn(prototype):
|
||||
if not "noloc" in self.switches and not "location" in prototype:
|
||||
prototype["location"] = self.caller.location
|
||||
|
||||
for obj in spawn(prototype, prototype_parents=_PROTOTYPE_PARENTS):
|
||||
self.caller.msg("Spawned %s." % obj.key)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ GOBLIN = {
|
|||
}
|
||||
|
||||
Possible keywords are:
|
||||
prototype - dict, parent prototype of this structure (see below)
|
||||
prototype - string parent prototype
|
||||
key - string, the main object identifier
|
||||
typeclass - string, if not set, will use settings.BASE_OBJECT_TYPECLASS
|
||||
location - this should be a valid object or #dbref
|
||||
|
|
@ -83,16 +83,16 @@ _CREATE_OBJECT_KWARGS = ("key", "location", "home", "destination")
|
|||
_handle_dbref = lambda inp: handle_dbref(inp, ObjectDB)
|
||||
|
||||
|
||||
def _get_prototype(dic, prot):
|
||||
def _get_prototype(dic, prot, protparents):
|
||||
"Recursively traverse a prototype dictionary, including multiple inheritance"
|
||||
if "prototype" in dic:
|
||||
# move backwards through the inheritance
|
||||
prototypes = dic["prototype"]
|
||||
if isinstance(prototypes, dict):
|
||||
if not hasattr(prototypes, "__iter__"):
|
||||
prototypes = (prototypes,)
|
||||
for prototype in prototypes:
|
||||
# Build the prot dictionary in reverse order, overloading
|
||||
new_prot = _get_prototype(prototype, prot)
|
||||
new_prot = _get_prototype(protparents.get(prototype, {}), prot, protparents)
|
||||
prot.update(new_prot)
|
||||
prot.update(dic)
|
||||
prot.pop("prototype", None) # we don't need this anymore
|
||||
|
|
@ -150,16 +150,21 @@ def _batch_create_object(*objparams):
|
|||
return objs
|
||||
|
||||
|
||||
def spawn(*prototypes):
|
||||
def spawn(*prototypes, **kwargs):
|
||||
"""
|
||||
Spawn a number of prototyped objects. Each argument should be a
|
||||
prototype dictionary.
|
||||
|
||||
The keyword argument "prototype_parents" holds a dictionary of
|
||||
prototype dictionaries, each with a unique key. The given
|
||||
prototypes may call these as parents using the "prototype" key.
|
||||
"""
|
||||
objsparams = []
|
||||
|
||||
for prototype in prototypes:
|
||||
protparents = kwargs.get("prototype_parents", None)
|
||||
|
||||
prot = _get_prototype(prototype, {})
|
||||
prot = _get_prototype(prototype, {}, protparents)
|
||||
if not prot:
|
||||
continue
|
||||
|
||||
|
|
@ -195,35 +200,32 @@ def spawn(*prototypes):
|
|||
if __name__ == "__main__":
|
||||
# testing
|
||||
|
||||
NOBODY = {}
|
||||
|
||||
GOBLIN = {
|
||||
"key": "goblin grunt",
|
||||
"health": lambda: randint(20,30),
|
||||
"resists": ["cold", "poison"],
|
||||
"attacks": ["fists"],
|
||||
"weaknesses": ["fire", "light"]
|
||||
}
|
||||
|
||||
GOBLIN_WIZARD = {
|
||||
"prototype": GOBLIN,
|
||||
"key": "goblin wizard",
|
||||
"spells": ["fire ball", "lighting bolt"]
|
||||
}
|
||||
|
||||
GOBLIN_ARCHER = {
|
||||
"prototype": GOBLIN,
|
||||
"key": "goblin archer",
|
||||
"attacks": ["short bow"]
|
||||
}
|
||||
|
||||
ARCHWIZARD = {
|
||||
"attacks": ["archwizard staff"],
|
||||
}
|
||||
|
||||
GOBLIN_ARCHWIZARD = {
|
||||
"key": "goblin archwizard",
|
||||
"prototype" : (GOBLIN_WIZARD, ARCHWIZARD)
|
||||
}
|
||||
protparents = {
|
||||
"NOBODY": {},
|
||||
"GOBLIN" : {
|
||||
"key": "goblin grunt",
|
||||
"health": lambda: randint(20,30),
|
||||
"resists": ["cold", "poison"],
|
||||
"attacks": ["fists"],
|
||||
"weaknesses": ["fire", "light"]
|
||||
},
|
||||
"GOBLIN_WIZARD" : {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin wizard",
|
||||
"spells": ["fire ball", "lighting bolt"]
|
||||
},
|
||||
"GOBLIN_ARCHER" : {
|
||||
"prototype": "GOBLIN",
|
||||
"key": "goblin archer",
|
||||
"attacks": ["short bow"]
|
||||
},
|
||||
"ARCHWIZARD" : {
|
||||
"attacks": ["archwizard staff"],
|
||||
},
|
||||
"GOBLIN_ARCHWIZARD" : {
|
||||
"key": "goblin archwizard",
|
||||
"prototype" : ("GOBLIN_WIZARD", "ARCHWIZARD")
|
||||
}
|
||||
}
|
||||
# test
|
||||
print [o.key for o in spawn(GOBLIN, GOBLIN_ARCHWIZARD)]
|
||||
print [o.key for o in spawn(protparents["GOBLIN"], protparents["GOBLIN_ARCHWIZARD"], prototype_parents=protparents)]
|
||||
|
|
|
|||
|
|
@ -792,6 +792,8 @@ def all_from_module(module):
|
|||
Return all global-level variables from a module as a dict
|
||||
"""
|
||||
mod = mod_import(module)
|
||||
if not mod:
|
||||
return {}
|
||||
return dict((key, val) for key, val in mod.__dict__.items()
|
||||
if not (key.startswith("_") or ismodule(val)))
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue