This repository has been archived by the owner on Feb 15, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dungeon.rb
156 lines (129 loc) · 4.89 KB
/
dungeon.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File: aeldardin-to-dot.rb
#
# Script to convert Aeldardin-Key YAML files into Dot .gv files representing the connection graph of the dungeon.
require 'yaml'
module Aeldardin
class Dungeon
# Represents a room within a dungeon
class Room
# Based off the OD&D random-dungeon-generation room types, but
# adjusted so each is a single room property:
# 'empty' is an absence of other properties, and 'monster and treasure'
# and 'trick or trap' each combine two types.
#
# Stored as strings rather than symbols so I can compare them to strings from user input.
# TODO: should probably ultimately be part of an OSR-specific plugin or something.
TYPES = %w[
monster
treasure
special
trick
trap
]
def initialize(data)
@data = data
end
def key
@data['key']
end
def name
@data['name']
end
def description
@data['description']
end
def exits
@data['exits'] || []
end
# Returns a list of the objects in the room,
# each as a hash with keys "item" (brief description), and
# "description" (what's noticed upon investigation).
def objects
@objects ||= begin
raw_objects = @data['objects'] || []
raw_objects.map do |object|
if object.is_a?(Hash)
# TODO: assumes it has the right keys.
object
else
{
item: object,
description: nil
}
end
end
end
end
# Similar to Gygax's room-type table in the OD&D random-dungeon rules
# (empty, monster, monster+treasure, special, trick or trap, treasure),
# but returns an array of types from TYPES.
#
# TODO: should I conver the return values to symbols?
def types
@data.keys & TYPES
end
end
# @param [IO] file The IO object to read YAML from.
def self.load(file)
# Load the whole dungeon into memory at once.
# TODO: this will fail for sufficently large dungeons.
# 'nil' means read all lines as one row.
yaml_text = file.readlines(nil)[0]
new(YAML.load(yaml_text))
end
# @param [Hash] data The dungeon data structure as described in the README, parsed into a Ruby object.
def initialize(data)
@data = data
end
# Accessor methods for dungeon properties
# We're only interested in read-only operation for the moment.
# The title of the overall dungeon.
def title
@data['title']
end
# The name of a specific region.
# Conceptually different -- title is grandiose, part of the "cover of the book",
# while name is utilitarian, summarising the region.
# Should possibly be combined anyway.
def name
@data['name']
end
# Consider regions and zones identical, and define them recursively.
# TODO: remove the distinct names from the data model.
def regions
# Use compact + flatten to combine the arrays in a nil-safe way (skip nil elements).
@regions ||= begin
all_regions = [@data['zones'], @data['regions']]
without_empties = all_regions.compact.flatten
without_empties.map { |region| Dungeon.new(region) }
end
end
# Rooms part of this dungeon directly, excluding those in child regions.
def local_rooms
@local_rooms ||= begin
room_hashes = @data['rooms'] || []
room_hashes.map { |hash| Room.new(hash) }
end
end
# All rooms, including children.
def rooms
@rooms ||= begin
child_rooms = regions.map(&:rooms).flatten
child_rooms + local_rooms
end
end
# Returns a lookup table from room keys (usually numbers) to the full room details.
def rooms_by_key
@rooms_by_key ||= begin
by_key = {}
rooms.each do |room|
if by_key.key?(room.key)
raise "Unexpected duplicate room #{room.key}: #{room.inspect}"
end
by_key[room.key] = room
end
by_key
end
end
end
end