More dungeon code
This commit is contained in:
parent
07ff42b77c
commit
6a4b14fb83
4 changed files with 64 additions and 24 deletions
|
|
@ -75,7 +75,12 @@ class EvAdventureDungeonExit(DefaultExit):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
dungeon_orchestrator = AttributeProperty(None, autocreate=False)
|
def at_object_creation(self):
|
||||||
|
"""
|
||||||
|
We want to block progressing forward unless the room is clear.
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.locks.add("traverse:not tag(not_clear, dungeon_room)")
|
||||||
|
|
||||||
def at_traverse(self, traversing_object, target_location, **kwargs):
|
def at_traverse(self, traversing_object, target_location, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
@ -84,7 +89,9 @@ class EvAdventureDungeonExit(DefaultExit):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if target_location == self.location:
|
if target_location == self.location:
|
||||||
self.destination = target_location = self.dungeon_orchestrator.new_room(self)
|
self.destination = target_location = self.location.db.dungeon_orchestrator.new_room(
|
||||||
|
self
|
||||||
|
)
|
||||||
super().at_traverse(traversing_object, target_location, **kwargs)
|
super().at_traverse(traversing_object, target_location, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -129,14 +136,16 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
|
||||||
)
|
)
|
||||||
self.unvisited_exits.append(out_exit.id)
|
self.unvisited_exits.append(out_exit.id)
|
||||||
|
|
||||||
def _generate_room(self, depth, coords):
|
def _generate_dungeon_room(self, depth, coords):
|
||||||
# TODO - determine what type of room to create here based on location and depth
|
# TODO - determine what type of room to create here based on location and depth
|
||||||
room_typeclass = EvAdventureDungeonRoom
|
room_typeclass = EvAdventureDungeonRoom
|
||||||
new_room = create.create_object(
|
new_room = create.create_object(
|
||||||
room_typeclass,
|
room_typeclass,
|
||||||
key="Dungeon room",
|
key="Dungeon room",
|
||||||
tags=((self.key, "dungeon_room"),),
|
attributes=(
|
||||||
attributes=(("xy_coord", coords, "dungeon_xygrid"),),
|
("xy_coords", coords, "dungeon_xygrid"),
|
||||||
|
("dungeon_orchestrator", self),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
return new_room
|
return new_room
|
||||||
|
|
||||||
|
|
@ -170,7 +179,7 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
|
||||||
# depth achieved.
|
# depth achieved.
|
||||||
depth = int(sqrt(new_x**2 + new_y**2))
|
depth = int(sqrt(new_x**2 + new_y**2))
|
||||||
|
|
||||||
new_room = self._generate_room(depth, (new_x, new_y))
|
new_room = self._generate_dungeon_room(depth, (new_x, new_y))
|
||||||
|
|
||||||
self.xy_grid[(new_x, new_y)] = new_room
|
self.xy_grid[(new_x, new_y)] = new_room
|
||||||
|
|
||||||
|
|
@ -182,7 +191,14 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
|
||||||
aliases=_EXIT_ALIASES.get(back_exit_key, ()),
|
aliases=_EXIT_ALIASES.get(back_exit_key, ()),
|
||||||
location=new_room,
|
location=new_room,
|
||||||
destination=from_exit.location,
|
destination=from_exit.location,
|
||||||
attributes=(("desc", "A dark passage."),),
|
attributes=(
|
||||||
|
(
|
||||||
|
"desc",
|
||||||
|
"A dark passage.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
# we default to allowing back-tracking (also used for fleeing)
|
||||||
|
locks=("traverse: true()",),
|
||||||
)
|
)
|
||||||
|
|
||||||
# figure out what other exits should be here, if any
|
# figure out what other exits should be here, if any
|
||||||
|
|
@ -205,8 +221,8 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
|
||||||
direction = available_directions.pop(0)
|
direction = available_directions.pop(0)
|
||||||
dx, dy = _EXIT_GRID_SHIFT[direction]
|
dx, dy = _EXIT_GRID_SHIFT[direction]
|
||||||
target_coord = (new_x + dx, new_y + dy)
|
target_coord = (new_x + dx, new_y + dy)
|
||||||
if target_coord not in self.xy_grid:
|
if target_coord not in self.xy_grid and target_coord != (0, 0):
|
||||||
# no room there - make an exit to it
|
# no room there (and not back to start room) - make an exit to it
|
||||||
self.create_out_exit(new_room, direction)
|
self.create_out_exit(new_room, direction)
|
||||||
# we create this to avoid other rooms linking here, but don't create the
|
# we create this to avoid other rooms linking here, but don't create the
|
||||||
# room yet
|
# room yet
|
||||||
|
|
@ -215,6 +231,8 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
|
||||||
|
|
||||||
self.highest_depth = max(self.highest_depth, depth)
|
self.highest_depth = max(self.highest_depth, depth)
|
||||||
|
|
||||||
|
return new_room
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------------------------
|
# --------------------------------------------------
|
||||||
# Start room
|
# Start room
|
||||||
|
|
@ -232,16 +250,11 @@ class EvAdventureStartRoomExit(DefaultExit):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# we store the orchestrator like this since we don't want to actually manipulate it,
|
|
||||||
# but only use the reference to know when to create a new room
|
|
||||||
dungeon_orchestrator = AttributeProperty(None, autocreate=False)
|
|
||||||
|
|
||||||
def reset_exit(self):
|
def reset_exit(self):
|
||||||
"""
|
"""
|
||||||
Flush the exit, so next traversal creates a new dungeon branch.
|
Flush the exit, so next traversal creates a new dungeon branch.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.dungeon_orchestrator = None
|
|
||||||
self.destination = self.location
|
self.destination = self.location
|
||||||
|
|
||||||
def at_traverse(self, traversing_object, target_location, **kwargs):
|
def at_traverse(self, traversing_object, target_location, **kwargs):
|
||||||
|
|
@ -249,12 +262,13 @@ class EvAdventureStartRoomExit(DefaultExit):
|
||||||
When traversing create a new orchestrator if one is not already assigned.
|
When traversing create a new orchestrator if one is not already assigned.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
if target_location == self.location or self.dungeon_orchestrator is None:
|
if target_location == self.location:
|
||||||
self.dungeon_orchestrator = create.create_script(
|
# make a global orchestrator script for this dungeon branch
|
||||||
|
dungeon_orchestrator = create.create_script(
|
||||||
EvAdventureDungeonOrchestrator,
|
EvAdventureDungeonOrchestrator,
|
||||||
key=f"dungeon_orchestrator_{self.key}_{datetime.utcnow()}",
|
key=f"dungeon_orchestrator_{self.key}_{datetime.utcnow()}",
|
||||||
)
|
)
|
||||||
self.destination = target_location = self.dungeon_orchestrator.new_room(self)
|
self.destination = target_location = dungeon_orchestrator.new_room(self)
|
||||||
|
|
||||||
super().at_traverse(traversing_object, target_location, **kwargs)
|
super().at_traverse(traversing_object, target_location, **kwargs)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ EvAdventure rooms.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from evennia import DefaultRoom
|
from evennia import AttributeProperty, DefaultRoom, TagProperty
|
||||||
|
|
||||||
|
|
||||||
class EvAdventureRoom(DefaultRoom):
|
class EvAdventureRoom(DefaultRoom):
|
||||||
|
|
@ -37,3 +37,29 @@ class EvAdventureDungeonRoom(EvAdventureRoom):
|
||||||
|
|
||||||
allow_combat = True
|
allow_combat = True
|
||||||
allow_death = True
|
allow_death = True
|
||||||
|
|
||||||
|
# dungeon generation attributes; set when room is created
|
||||||
|
back_exit = AttributeProperty(None, autocreate=False)
|
||||||
|
dungeon_orchestrator = AttributeProperty(None, autocreate=False)
|
||||||
|
xy_coords = AttributeProperty(None, autocreate=False)
|
||||||
|
|
||||||
|
def at_object_creation(self):
|
||||||
|
"""
|
||||||
|
Set the `not_clear` tag on the room. This is removed when the room is
|
||||||
|
'cleared', whatever that means for each room.
|
||||||
|
|
||||||
|
We put this here rather than in the room-creation code so we can override
|
||||||
|
easier (for example we may want an empty room which auto-clears).
|
||||||
|
|
||||||
|
"""
|
||||||
|
self.tags.add("not_clear")
|
||||||
|
|
||||||
|
def get_display_footer(self, looker, **kwargs):
|
||||||
|
"""
|
||||||
|
Show if the room is 'cleared' or not as part of its description.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if self.tags.get("not_clear", "dungeon_room"):
|
||||||
|
# this tag is cleared when the room is resolved, whatever that means.
|
||||||
|
return "|rThe path forwards is blocked!|n"
|
||||||
|
return ""
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest):
|
||||||
if exi.key == direction:
|
if exi.key == direction:
|
||||||
# by setting target to old-location we trigger the
|
# by setting target to old-location we trigger the
|
||||||
# special behavior of this Exit type
|
# special behavior of this Exit type
|
||||||
exi.at_traverse(self.character, old_location)
|
exi.at_traverse(self.character, exi.destination)
|
||||||
break
|
break
|
||||||
return self.character.location
|
return self.character.location
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest):
|
||||||
self.assertTrue(inherits_from(new_room_north, EvAdventureDungeonRoom))
|
self.assertTrue(inherits_from(new_room_north, EvAdventureDungeonRoom))
|
||||||
|
|
||||||
# check if Orchestrator was created
|
# check if Orchestrator was created
|
||||||
orchestrator = self.start_north.scripts.get(dungeon.EvAdventureDungeonOrchestrator)
|
orchestrator = new_room_north.db.dungeon_orchestrator
|
||||||
self.assertTrue(bool(orchestrator))
|
self.assertTrue(bool(orchestrator))
|
||||||
self.assertTrue(orchestrator.key.startswith("dungeon_orchestrator_north_"))
|
self.assertTrue(orchestrator.key.startswith("dungeon_orchestrator_north_"))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,15 @@ the database object. Like everything else, they can be accessed
|
||||||
transparently through the decorating TypeClass.
|
transparently through the decorating TypeClass.
|
||||||
"""
|
"""
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db import models
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.validators import validate_comma_separated_integer_list
|
from django.core.validators import validate_comma_separated_integer_list
|
||||||
|
from django.db import models
|
||||||
from evennia.typeclasses.models import TypedObject
|
|
||||||
from evennia.objects.manager import ObjectDBManager
|
from evennia.objects.manager import ObjectDBManager
|
||||||
|
from evennia.typeclasses.models import TypedObject
|
||||||
from evennia.utils import logger
|
from evennia.utils import logger
|
||||||
from evennia.utils.utils import make_iter, dbref, lazy_property
|
from evennia.utils.utils import dbref, lazy_property, make_iter
|
||||||
|
|
||||||
|
|
||||||
class ContentsHandler:
|
class ContentsHandler:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue