mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 22:06:30 +01:00
141 lines
5.3 KiB
ReStructuredText
141 lines
5.3 KiB
ReStructuredText
Zones
|
|
=====
|
|
|
|
Problem
|
|
-------
|
|
|
|
Say you create a room named *Meadow* in your nice big forest MUD. That's
|
|
all nice and dandy, but what if you, in the other end of that forest
|
|
want another *Meadow*? As a game creator, this can cause all sorts of
|
|
confusion. For example, teleporting to *Meadow* will now give you a
|
|
warning that there are two *Meadow* s and you have to select which one.
|
|
It's no problem to do that, you just choose for example to go to
|
|
``2-meadow``, but unless you examine them you couldn't be sure which of
|
|
the two sat in the magical part of the forest and which didn't.
|
|
|
|
Another issue is if you want to group rooms in geographic regions for
|
|
example. Let's say the "normal" part of the forest should have separate
|
|
weather patterns from the magical part. Or maybe a magical disturbance
|
|
echoes through all magical-forest rooms. It would then be convenient to
|
|
be able to simply find all rooms that are "magical" so you could send
|
|
messages to them.
|
|
|
|
Zones in Evennia
|
|
----------------
|
|
|
|
*Zones* try to separate rooms by global location. In our example we
|
|
would separate the forest into two parts - the magical and the
|
|
non-magical part. Each have a *Meadow* and rooms belonging to each part
|
|
should be easy to retrieve.
|
|
|
|
Many MUD codebases hardcode zones as part of the engine and database.
|
|
Evennia does no such distinction due to the fact that rooms themselves
|
|
are meant to be customized to any level anyway. Below is just *one*
|
|
example of how one could add zone-like functionality to a game.
|
|
|
|
All objects have a *key* property, stored in the database. This is the
|
|
primary name of the object. But it can also have any number of *Aliases*
|
|
connected to itself. This allows Players to refer to the object using
|
|
both key and alias - a "big red door" can also be referred to as the
|
|
alias "door". Aliases are actually separate database entities and are as
|
|
such very fast to search for in the database, about as fast as searching
|
|
for the object's primary key in fact.
|
|
|
|
This makes Aliases prime candiates for implementing zones. All you need
|
|
to do is to come up with a consistent aliasing scheme. Here's one
|
|
suggestion:
|
|
|
|
::
|
|
|
|
#zonename|key
|
|
|
|
So say we (arbitrarily) divide our forest example into the zones
|
|
``magicforest`` and ``normalforest``. These are the added aliases we use
|
|
for the respective *Meadow* 's:
|
|
|
|
::
|
|
|
|
#magicforest|meadow
|
|
#normalforest|meadow
|
|
|
|
The primary key of each will still be *Meadow*, and players will still
|
|
see that name. We can also add any number of other Aliases to each
|
|
meadow if we want. But we will also henceforth always be able to
|
|
uniquely identify the right meadow by prepending its primary key name
|
|
with ``#zonename|``.
|
|
|
|
Enforcing zones
|
|
---------------
|
|
|
|
Maybe you feel that this usage of aliases for zones is somehow loose and
|
|
ad-hoc. It is, and there is no guarantee that a builder would follow the
|
|
naming convention - unless you force them. And you can do that easily by
|
|
changing for example the ``@dig`` `Command <Commands.html>`_ to require
|
|
the zone to be given:
|
|
|
|
::
|
|
|
|
@dig zone|roomname:typeclass = north;n, south;s
|
|
|
|
Just have the ``@dig`` command auto-add an alias of the correct format
|
|
and hey-presto! A functioning zone system! An even more convenient way
|
|
to enforce zones would be for the new room to inherit the zone from the
|
|
room we are building from.
|
|
|
|
Overload the default ``search`` method on a typeclass for further
|
|
functionality:
|
|
|
|
::
|
|
|
|
def search(self, ostring, zone=None, *args, **kwargs):
|
|
if zone:
|
|
ostring = "#%s|%s" % (ostring, zone)
|
|
return self.dbobj.search(ostring, *args, **kwargs)
|
|
|
|
You will then be able to do, from commands:
|
|
|
|
::
|
|
|
|
meadow_obj = self.caller.search("meadow", zone="magicforest")
|
|
|
|
and be sure you are getting the magical meadow, not the normal one.
|
|
|
|
You could also easily build search queries searching only for rooms with
|
|
aliases starting with ``#magicforest|``. This would allow for easy
|
|
grouping and retrieving of all rooms in a zone for whatever need to
|
|
have.
|
|
|
|
Evennia's open solution to zones means that you have much more power
|
|
than in most MUD systems. There is for example no reason why you have to
|
|
group and organize only rooms with this scheme.
|
|
|
|
Using typeclasses and inheritance for zoning
|
|
--------------------------------------------
|
|
|
|
The above alias scheme is basically a way to easily find and group
|
|
objects together at run-time - a way to label, if you will. It doesn't
|
|
instill any sort of functional difference between a magical forest room
|
|
and a normal one. For this you will need to use Typeclasses. If you know
|
|
that a certain typeclass of room will always be in a certain zone you
|
|
could even hard-code the zone in the typeclass rather than enforce the
|
|
``@dig`` command to do it:
|
|
|
|
::
|
|
|
|
class MagicalForestRoom(Room)
|
|
def at_object_creation(self):
|
|
...
|
|
self.aliases = "#magicforest|%s" % self.key
|
|
...
|
|
class NormalForestRoom(Room)
|
|
def at_object_creation(self):
|
|
...
|
|
self.aliases = "#normalforest|%s" % self.key
|
|
...
|
|
|
|
Of course, an alternative way to implement zones themselves is to have
|
|
all rooms/objects in a zone inherit from a given typeclass parent - and
|
|
then limit your searches to objects inheriting from that given parent.
|
|
The effect would be the same and you wouldn't need to implement any
|
|
ad-hoc aliasing scheme; but you'd need to expand the search
|
|
functionality to properly search the inheritance tree.
|