update wilderness contrib

This commit is contained in:
InspectorCaracal 2022-11-21 17:34:40 -07:00
parent 86318b7559
commit a69f416162

View file

@ -34,10 +34,11 @@ The defaults, while useable, are meant to be customised. When creating a
new wilderness map it is possible to give a "map provider": this is a new wilderness map it is possible to give a "map provider": this is a
python object that is smart enough to create the map. python object that is smart enough to create the map.
The default provider, `WildernessMapProvider`, just creates a grid area that The default provider, `WildernessMapProvider`, creates a grid area that
is unlimited in size. is unlimited in size.
This `WildernessMapProvider` can be subclassed to create more interesting
maps and also to customize the room/exit typeclass used. `WildernessMapProvider` can be subclassed to create more interesting maps
and also to customize the room/exit typeclass used.
There is also no command that allows players to enter the wilderness. This There is also no command that allows players to enter the wilderness. This
still needs to be added: it can be a command or an exit, depending on your still needs to be added: it can be a command or an exit, depending on your
@ -121,7 +122,7 @@ from evennia import (
create_script, create_script,
) )
from evennia.utils import inherits_from from evennia.utils import inherits_from
from evennia.typeclasses.attributes import AttributeProperty
def create_wilderness(name="default", mapprovider=None): def create_wilderness(name="default", mapprovider=None):
""" """
@ -161,10 +162,12 @@ def enter_wilderness(obj, coordinates=(0, 0), name="default"):
Returns: Returns:
bool: True if obj successfully moved into the wilderness. bool: True if obj successfully moved into the wilderness.
""" """
if not WildernessScript.objects.filter(db_key=name).exists(): script = WildernessScript.objects.filter(db_key=name)
if not script.exists():
return False return False
else:
script = script[0]
script = WildernessScript.objects.get(db_key=name)
if script.is_valid_coordinates(coordinates): if script.is_valid_coordinates(coordinates):
script.move_obj(obj, coordinates) script.move_obj(obj, coordinates)
return True return True
@ -205,6 +208,18 @@ class WildernessScript(DefaultScript):
into storage when they are not needed anymore. into storage when they are not needed anymore.
""" """
# Stores the MapProvider class
mapprovider = AttributeProperty()
# Stores a dictionary of items on the map with their coordinates
# The key is the item, the value are the coordinates as (x, y) tuple.
itemcoordinates = AttributeProperty()
# Determines whether or not rooms are recycled despite containing non-player objects
# True means that leaving behind a non-player object will prevent the room from being recycled
# in order to preserve the object
preserve_items = AttributeProperty(default=False)
def at_script_creation(self): def at_script_creation(self):
""" """
Only called once, when the script is created. This is a default Evennia Only called once, when the script is created. This is a default Evennia
@ -225,38 +240,15 @@ class WildernessScript(DefaultScript):
# create it. # create it.
self.db.unused_rooms = [] self.db.unused_rooms = []
@property def at_server_start(self):
def mapprovider(self):
""" """
Shortcut property to the map provider. Called after the server is started or reloaded.
Returns:
MapProvider: the mapprovider used with this wilderness
"""
return self.db.mapprovider
@property
def itemcoordinates(self):
"""
Returns a dictionary with the coordinates of every item inside this
wilderness map. The key is the item, the value are the coordinates as
(x, y) tuple.
Returns:
{item: coordinates}
"""
return self.db.itemcoordinates
def at_start(self):
"""
Called when the script is started and also after server reloads.
""" """
for coordinates, room in self.db.rooms.items(): for coordinates, room in self.db.rooms.items():
room.ndb.wildernessscript = self room.ndb.wildernessscript = self
room.ndb.active_coordinates = coordinates room.ndb.active_coordinates = coordinates
for item in list(self.db.itemcoordinates.keys()): for item in self.db.itemcoordinates.keys():
# Items deleted from the wilderness leave None type 'ghosts' # Items deleted from the wilderness can leave None type 'ghosts'
# that must be cleaned out
if item is None: if item is None:
del self.db.itemcoordinates[item] del self.db.itemcoordinates[item]
continue continue
@ -303,15 +295,7 @@ class WildernessScript(DefaultScript):
Returns: Returns:
[Object, ]: list of Objects at coordinates [Object, ]: list of Objects at coordinates
""" """
result = [] result = [ item for item, item_coords in self.itemcoordinates.items() if item_coords == coordinates and item is not None ]
for item, item_coordinates in list(self.itemcoordinates.items()):
# Items deleted from the wilderness leave None type 'ghosts'
# that must be cleaned out
if item is None:
del self.db.itemcoordinates[item]
continue
if coordinates == item_coordinates:
result.append(item)
return result return result
def move_obj(self, obj, new_coordinates): def move_obj(self, obj, new_coordinates):
@ -330,44 +314,37 @@ class WildernessScript(DefaultScript):
# appear in its old room should that room be deleted. # appear in its old room should that room be deleted.
obj.location = None obj.location = None
try: # By default, we'll assume we won't be making a new room and change this flag if necessary.
create_room = False
# See if we already have a room for that location # See if we already have a room for that location
room = self.db.rooms[new_coordinates] if room := self.db.rooms.get(new_coordinates):
# There is. Try to destroy the old_room if it is not needed anymore # There is. Try to destroy the old_room if it is not needed anymore
self._destroy_room(old_room) self._destroy_room(old_room)
except KeyError: else:
# There is no room yet at new_location # There is no room yet at new_location
if (old_room and not inherits_from(old_room, WildernessRoom)) or (not old_room): # Is the old room in this wilderness?
# Obj doesn't originally come from a wilderness room. if old_room in self.db.rooms.keys():
# We'll create a new one then. # Is there anything still left in the old_room, besides the exits?
if len([ob for ob in old_room.contents if not inherits_from(ob, WildernessExit)]):
# There is, so we'll create a new room
room = self._create_room(new_coordinates, obj) room = self._create_room(new_coordinates, obj)
else: else:
# Obj does come from another wilderness room # The room is empty, so we'll just reuse it
create_new_room = False
if old_room.wilderness != self:
# ... but that other wilderness room belongs to another
# wilderness map
create_new_room = True
old_room.wilderness.at_post_object_leave(obj)
else:
for item in old_room.contents:
if item.has_account:
# There is still a player in the old room.
# Let's create a new room and not touch that old
# room.
create_new_room = True
break
if create_new_room:
# Create a new room to hold obj, not touching any obj's in
# the old room
room = self._create_room(new_coordinates, obj)
else:
# The old_room is empty: we are just going to reuse that
# room instead of creating a new one
room = old_room room = old_room
# Is the previous room from a different wilderness?
elif inherits_from(old_room, WildernessRoom) and old_room.wilderness != self:
# It does, so we make sure to leave the other wilderness properly
old_room.wilderness.at_post_object_leave(obj)
# We'll also need to create a new room in this wilderness
room = self._create_room(new_coordinates, obj)
else:
# Obj comes from outside the wilderness entirely
# We need to make a new room
room = self._create_room(new_coordinates, obj)
room.set_active_coordinates(new_coordinates, obj) room.set_active_coordinates(new_coordinates, obj)
obj.location = room obj.location = room
obj.ndb.wilderness = self obj.ndb.wilderness = self
@ -425,7 +402,11 @@ class WildernessScript(DefaultScript):
def _destroy_room(self, room): def _destroy_room(self, room):
""" """
Moves a room back to storage. If room is not a WildernessRoom or there Moves a room back to storage. If room is not a WildernessRoom or there
is a player inside the room, then this does nothing. is something left inside the room, then this does nothing.
Implementation note: If `preserve_items` is False (the default) then any
objects left in the rooms will be moved to None. You may want to implement
your own cleanup or recycling routine for these objects.
Args: Args:
room (WildernessRoom): the room to put in storage room (WildernessRoom): the room to put in storage
@ -433,22 +414,27 @@ class WildernessScript(DefaultScript):
if not room or not inherits_from(room, WildernessRoom): if not room or not inherits_from(room, WildernessRoom):
return return
# Check the contents of the room before recycling
for item in room.contents: for item in room.contents:
if item.has_account: if item.has_account:
# There is still a character in that room. We can't get rid of # There is still a player in this room, we can't delete it yet.
# it just yet return
break
else:
# No characters left in the room.
# Clear the location of every obj in that room first if not (item.destination and item.destination == room):
# There is still a non-exit object in the room. Should we preserve it?
if self.preserve_items:
# Yes, so we can't get rid of the room just yet
return
# If we get here, the room can be recycled
# Clear the location of any objects left in that room first
for item in room.contents: for item in room.contents:
if item.destination and item.destination == room: if item.destination and item.destination == room:
# Ignore the exits, they stay in the room # Ignore the exits, they stay in the room
continue continue
item.location = None item.location = None
# Then delete its reference # Then delete its coordinate reference
del self.db.rooms[room.ndb.active_coordinates] del self.db.rooms[room.ndb.active_coordinates]
# And finally put this room away in storage # And finally put this room away in storage
self.db.unused_rooms.append(room) self.db.unused_rooms.append(room)
@ -460,12 +446,12 @@ class WildernessScript(DefaultScript):
Args: Args:
obj (object): the object that left obj (object): the object that left
""" """
# Remove that obj from the wilderness's coordinates dict # Try removing the object from the coordinates system
loc = self.db.itemcoordinates[obj] if loc := self.db.itemcoordinates.pop(obj, None):
del self.db.itemcoordinates[obj] # The object was removed successfully
# Make sure there was a room at that location
# And see if we can put that room away into storage. if room := self.db.rooms.get(loc):
room = self.db.rooms[loc] # If so, try to clean up the room
self._destroy_room(room) self._destroy_room(room)