More dungeon code

This commit is contained in:
Griatch 2022-07-24 13:01:01 +02:00
parent 07ff42b77c
commit 6a4b14fb83
4 changed files with 64 additions and 24 deletions

View file

@ -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):
"""
@ -84,7 +89,9 @@ class EvAdventureDungeonExit(DefaultExit):
"""
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)
@ -129,14 +136,16 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
)
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
room_typeclass = EvAdventureDungeonRoom
new_room = create.create_object(
room_typeclass,
key="Dungeon room",
tags=((self.key, "dungeon_room"),),
attributes=(("xy_coord", coords, "dungeon_xygrid"),),
attributes=(
("xy_coords", coords, "dungeon_xygrid"),
("dungeon_orchestrator", self),
),
)
return new_room
@ -170,7 +179,7 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
# depth achieved.
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
@ -182,7 +191,14 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
aliases=_EXIT_ALIASES.get(back_exit_key, ()),
location=new_room,
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
@ -205,8 +221,8 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
direction = available_directions.pop(0)
dx, dy = _EXIT_GRID_SHIFT[direction]
target_coord = (new_x + dx, new_y + dy)
if target_coord not in self.xy_grid:
# no room there - make an exit to it
if target_coord not in self.xy_grid and target_coord != (0, 0):
# no room there (and not back to start room) - make an exit to it
self.create_out_exit(new_room, direction)
# we create this to avoid other rooms linking here, but don't create the
# room yet
@ -215,6 +231,8 @@ class EvAdventureDungeonOrchestrator(DefaultScript):
self.highest_depth = max(self.highest_depth, depth)
return new_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):
"""
Flush the exit, so next traversal creates a new dungeon branch.
"""
self.dungeon_orchestrator = None
self.destination = self.location
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.
"""
if target_location == self.location or self.dungeon_orchestrator is None:
self.dungeon_orchestrator = create.create_script(
if target_location == self.location:
# make a global orchestrator script for this dungeon branch
dungeon_orchestrator = create.create_script(
EvAdventureDungeonOrchestrator,
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)

View file

@ -5,7 +5,7 @@ EvAdventure rooms.
"""
from evennia import DefaultRoom
from evennia import AttributeProperty, DefaultRoom, TagProperty
class EvAdventureRoom(DefaultRoom):
@ -37,3 +37,29 @@ class EvAdventureDungeonRoom(EvAdventureRoom):
allow_combat = 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 ""

View file

@ -56,7 +56,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest):
if exi.key == direction:
# by setting target to old-location we trigger the
# special behavior of this Exit type
exi.at_traverse(self.character, old_location)
exi.at_traverse(self.character, exi.destination)
break
return self.character.location
@ -74,7 +74,7 @@ class TestDungeon(EvAdventureMixin, BaseEvenniaTest):
self.assertTrue(inherits_from(new_room_north, EvAdventureDungeonRoom))
# 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(orchestrator.key.startswith("dungeon_orchestrator_north_"))