ifmapper 0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.txt +2 -0
- data/IFMapper.gemspec +21 -0
- data/IFMapper.rb +27 -0
- data/icons/copy.png +0 -0
- data/icons/cut.png +0 -0
- data/icons/filenew.png +0 -0
- data/icons/fileopen.png +0 -0
- data/icons/filesave.png +0 -0
- data/icons/filesaveas.png +0 -0
- data/icons/help.png +0 -0
- data/icons/kill.png +0 -0
- data/icons/nextpage.png +0 -0
- data/icons/paste.png +0 -0
- data/icons/prevpage.png +0 -0
- data/icons/printicon.png +0 -0
- data/icons/redo.png +0 -0
- data/icons/saveas.png +0 -0
- data/icons/undo.png +0 -0
- data/icons/winapp.png +0 -0
- data/icons/zoom.png +0 -0
- data/lib/IFMapper/Connection.rb +63 -0
- data/lib/IFMapper/FXAboutDialogBox.rb +32 -0
- data/lib/IFMapper/FXConnection.rb +283 -0
- data/lib/IFMapper/FXConnectionDialogBox.rb +126 -0
- data/lib/IFMapper/FXMap.rb +1614 -0
- data/lib/IFMapper/FXMapDialogBox.rb +51 -0
- data/lib/IFMapper/FXMapFileDialog.rb +29 -0
- data/lib/IFMapper/FXMapperSettings.rb +45 -0
- data/lib/IFMapper/FXMapperWindow.rb +1051 -0
- data/lib/IFMapper/FXPage.rb +24 -0
- data/lib/IFMapper/FXPageDialogBox.rb +38 -0
- data/lib/IFMapper/FXRoom.rb +218 -0
- data/lib/IFMapper/FXRoomDialogBox.rb +119 -0
- data/lib/IFMapper/FXSearchDialogBox.rb +51 -0
- data/lib/IFMapper/FXSpline.rb +54 -0
- data/lib/IFMapper/FXWarningBox.rb +45 -0
- data/lib/IFMapper/IFMReader.rb +613 -0
- data/lib/IFMapper/Map.rb +110 -0
- data/lib/IFMapper/PDFMapExporter.rb +315 -0
- data/lib/IFMapper/Page.rb +158 -0
- data/lib/IFMapper/Room.rb +104 -0
- data/maps/Bureaucracy.ifm +75 -0
- data/maps/Hollywood_Hijinx.ifm +149 -0
- data/maps/Jigsaw.ifm +806 -0
- data/maps/LGOP.ifm +705 -0
- data/maps/Mercy.ifm +76 -0
- data/maps/Planetfall.ifm +186 -0
- data/maps/Plundered_Hearts.ifm +251 -0
- data/maps/Ralph.ifm +50 -0
- data/maps/Robots_of_Dawn.ifm +224 -0
- data/maps/Seastalker.ifm +149 -0
- data/maps/Sherlock.ifm +209 -0
- data/maps/SoFar.ifm +72 -0
- data/maps/Starcross.ifm +170 -0
- data/maps/Suspended.ifm +82 -0
- data/maps/Wishbringer.ifm +277 -0
- data/maps/Wishbringer2.ifm +246 -0
- data/maps/Zork1.ifm +410 -0
- data/maps/Zork2.ifm +150 -0
- data/maps/Zork3.ifm +136 -0
- data/maps/Zork_Zero.ifm +557 -0
- data/maps/anchor.ifm +645 -0
- data/maps/atrox.ifm +134 -0
- data/maps/awaken.ifm +116 -0
- data/maps/babel.ifm +279 -0
- data/maps/bse.ifm +150 -0
- data/maps/change.ifm +128 -0
- data/maps/curses.ifm +307 -0
- data/maps/curves.ifm +529 -0
- data/maps/edifice.ifm +158 -0
- data/maps/frozen.ifm +126 -0
- data/maps/glow.ifm +101 -0
- data/maps/library.ifm +93 -0
- data/maps/mindelec.ifm +89 -0
- data/maps/minster.ifm +234 -0
- data/maps/muse.ifm +154 -0
- data/maps/paperchase.ifm +110 -0
- data/maps/space_st.ifm +104 -0
- data/maps/stationfall.ifm +320 -0
- data/maps/theatre.ifm +182 -0
- data/maps/toonesia.ifm +54 -0
- data/maps/tortoise.ifm +72 -0
- data/maps/vgame.ifm +219 -0
- data/maps/weather.ifm +98 -0
- data/maps/windhall.ifm +154 -0
- data/maps/zebulon.ifm +68 -0
- metadata +144 -0
data/lib/IFMapper/Map.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'IFMapper/Room'
|
4
|
+
require 'IFMapper/Page'
|
5
|
+
|
6
|
+
class Map
|
7
|
+
attr_accessor :name
|
8
|
+
attr_accessor :creator
|
9
|
+
attr_accessor :date
|
10
|
+
|
11
|
+
attr_reader :page
|
12
|
+
attr_accessor :pages
|
13
|
+
|
14
|
+
attr_accessor :width
|
15
|
+
attr_accessor :height
|
16
|
+
|
17
|
+
def page=(x)
|
18
|
+
x = 0 if x < 0
|
19
|
+
x = @pages.size - 1 if x >= @pages.size
|
20
|
+
@page = x
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Used for loading class with Marshal
|
25
|
+
#
|
26
|
+
def marshal_load(v)
|
27
|
+
@name = v.shift
|
28
|
+
@creator = v.shift
|
29
|
+
@date = v.shift
|
30
|
+
@page = v.shift
|
31
|
+
@pages = v.shift
|
32
|
+
@width = v.shift
|
33
|
+
@height = v.shift
|
34
|
+
end
|
35
|
+
|
36
|
+
#
|
37
|
+
# Used for saving class with Marshal
|
38
|
+
#
|
39
|
+
def marshal_dump
|
40
|
+
[ @name, @creator, @date, @page, @pages, @width, @height ]
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(name)
|
44
|
+
@page = 0
|
45
|
+
@name = name
|
46
|
+
@creator = ''
|
47
|
+
|
48
|
+
# if printing sideways
|
49
|
+
@width = 20
|
50
|
+
@height = 20
|
51
|
+
|
52
|
+
# Add at least one page
|
53
|
+
@pages = []
|
54
|
+
new_page
|
55
|
+
end
|
56
|
+
|
57
|
+
def copy(b)
|
58
|
+
@page = b.page
|
59
|
+
@pages = b.pages
|
60
|
+
@name = b.name
|
61
|
+
@creator = b.creator
|
62
|
+
@width = b.width
|
63
|
+
@height = b.height
|
64
|
+
@date = b.date
|
65
|
+
end
|
66
|
+
|
67
|
+
def delete_connection(c)
|
68
|
+
@pages[@page].delete_connection(c)
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete_connection_at( idx )
|
72
|
+
@pages[@page].delete_connection_at(idx)
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def new_connection( roomA, exitA, roomB, exitB = nil )
|
77
|
+
@pages[@page].new_connection(roomA, exitA, roomB, exitB)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
def delete_room_at(idx)
|
82
|
+
@pages[@page].delete_room_at(idx)
|
83
|
+
end
|
84
|
+
|
85
|
+
def delete_room(r)
|
86
|
+
@pages[@page].delete_room(r)
|
87
|
+
end
|
88
|
+
|
89
|
+
def new_room( x, y )
|
90
|
+
@pages[@page].new_room(x, y)
|
91
|
+
end
|
92
|
+
|
93
|
+
def new_page
|
94
|
+
@pages.push( Page.new )
|
95
|
+
@page = @pages.size - 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def _check_page
|
99
|
+
@page = @pages.size - 1 if @page >= @pages.size
|
100
|
+
new_page if @pages.size == 0
|
101
|
+
end
|
102
|
+
|
103
|
+
def delete_page_at(idx)
|
104
|
+
@pages.delete_at(idx)
|
105
|
+
_check_page
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
|
@@ -0,0 +1,315 @@
|
|
1
|
+
|
2
|
+
begin
|
3
|
+
require 'tmpdir'
|
4
|
+
rescue => e
|
5
|
+
raise "Please install 'tmpdir' library. This is needed for printing."
|
6
|
+
end
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'pdf/writer'
|
10
|
+
rescue => e
|
11
|
+
raise "Please install 'pdf writer' library for Acrobat PDF support."
|
12
|
+
end
|
13
|
+
|
14
|
+
PDF_ZOOM = 0.5
|
15
|
+
PDF_ROOM_WIDTH = W * PDF_ZOOM # 60
|
16
|
+
PDF_ROOM_HEIGHT = H * PDF_ZOOM # 37.5
|
17
|
+
PDF_ROOM_WS = WS * PDF_ZOOM
|
18
|
+
PDF_ROOM_HS = HS * PDF_ZOOM
|
19
|
+
PDF_MARGIN = 20
|
20
|
+
|
21
|
+
|
22
|
+
#
|
23
|
+
# Open all the map class and add all pdf methods there
|
24
|
+
# Gotta love Ruby's flexibility to just inject in new methods.
|
25
|
+
#
|
26
|
+
class FXConnection
|
27
|
+
def _cvt_pt(p, opts)
|
28
|
+
x = (p[0] - WW / 2.0) / WW.to_f
|
29
|
+
y = (p[1] - HH / 2.0) / HH.to_f
|
30
|
+
x = x * opts['ww'] + opts['ws_2'] + opts['margin_2'] + opts['w'] / 2.0
|
31
|
+
y = (opts['height'] - y) * opts['hh'] + opts['hs_2'] + opts['margin_2'] + opts['hs']
|
32
|
+
return [x, y]
|
33
|
+
end
|
34
|
+
|
35
|
+
def pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
36
|
+
return if @dir == BOTH
|
37
|
+
|
38
|
+
pt1, d = _arrow_info( x1, y1, x2, y2, 0.5 )
|
39
|
+
|
40
|
+
p = []
|
41
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0], pt1[1] )
|
42
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0] + d[0], pt1[1] - d[1] )
|
43
|
+
p << PDF::Writer::PolygonPoint.new( pt1[0] + d[1], pt1[1] + d[0] )
|
44
|
+
pdf.fill_color Color::RGB::Black
|
45
|
+
pdf.polygon(p).fill
|
46
|
+
end
|
47
|
+
|
48
|
+
def pdf_draw_complex_as_bspline( pdf, opts )
|
49
|
+
p = []
|
50
|
+
p << _cvt_pt(@pts[0], opts)
|
51
|
+
p << p[0]
|
52
|
+
p << p[0]
|
53
|
+
@pts.each { |pt|
|
54
|
+
p << _cvt_pt(pt, opts)
|
55
|
+
}
|
56
|
+
p << p[-1]
|
57
|
+
p << p[-1]
|
58
|
+
p << p[-1]
|
59
|
+
return FXSpline::bspline(p)
|
60
|
+
end
|
61
|
+
|
62
|
+
def pdf_draw_complex_as_lines( pdf, opts )
|
63
|
+
p = []
|
64
|
+
maxy = opts['height'] * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
65
|
+
@pts.each { |pt|
|
66
|
+
p << [ pt[0] * PDF_ZOOM, maxy - pt[1] * PDF_ZOOM ]
|
67
|
+
}
|
68
|
+
return p
|
69
|
+
end
|
70
|
+
|
71
|
+
def pdf_draw_complex( pdf, opts )
|
72
|
+
if opts['Paths as Curves']
|
73
|
+
p = pdf_draw_complex_as_bspline( pdf, opts )
|
74
|
+
else
|
75
|
+
p = pdf_draw_complex_as_lines( pdf, opts )
|
76
|
+
end
|
77
|
+
pdf.move_to( p[0][0], p[0][1] )
|
78
|
+
p.each { |pt| pdf.line_to( pt[0], pt[1] ) }
|
79
|
+
pdf.stroke
|
80
|
+
|
81
|
+
x1, y1 = [p[0][0], p[0][1]]
|
82
|
+
x2, y2 = [p[-1][0], p[-1][1]]
|
83
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
84
|
+
end
|
85
|
+
|
86
|
+
def pdf_draw_simple(pdf, opts)
|
87
|
+
return if not @roomB # PDF does not print unfinished complex connections
|
88
|
+
|
89
|
+
dir = @roomA.exits.index(self)
|
90
|
+
x1, y1 = @roomA.pdf_corner(pdf, opts, self, dir)
|
91
|
+
x2, y2 = @roomB.pdf_corner(pdf, opts, self)
|
92
|
+
pdf.move_to(x1, y1)
|
93
|
+
pdf.line_to(x2, y2).stroke
|
94
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
95
|
+
if @type == LOCKED_DOOR
|
96
|
+
v = [ (x2-x1)*0.25, (y2-y1)*0.25 ]
|
97
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
98
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
99
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
100
|
+
pdf.move_to(x1, y1)
|
101
|
+
pdf.line_to(x2, y2).stroke
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def pdf_draw(pdf, opts)
|
106
|
+
# pdf_draw_exit_text(pdf, opts)
|
107
|
+
if @type == SPECIAL
|
108
|
+
s = PDF::Writer::StrokeStyle.new(2, :dash => {
|
109
|
+
:pattern => [2],
|
110
|
+
:phase => [1]
|
111
|
+
} )
|
112
|
+
else
|
113
|
+
s = PDF::Writer::StrokeStyle.new(2,
|
114
|
+
:cap => :butt,
|
115
|
+
:join => :miter,
|
116
|
+
:dash => PDF::Writer::StrokeStyle::SOLID_LINE )
|
117
|
+
end
|
118
|
+
pdf.stroke_style( s )
|
119
|
+
pdf.stroke_color Color::RGB::Black
|
120
|
+
pdf.fill_color Color::RGB::White
|
121
|
+
if @pts.size > 0
|
122
|
+
pdf_draw_complex(pdf, opts)
|
123
|
+
else
|
124
|
+
pdf_draw_simple(pdf, opts)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
class FXRoom
|
131
|
+
def pdf_corner( pdf, opts, c, idx = nil )
|
132
|
+
x, y = _corner(c, idx)
|
133
|
+
y = -y
|
134
|
+
|
135
|
+
ww = opts['ww']
|
136
|
+
hh = opts['hh']
|
137
|
+
w = opts['w']
|
138
|
+
h = opts['h']
|
139
|
+
|
140
|
+
ry = opts['height'] - @y
|
141
|
+
x = @x * ww + opts['ws_2'] + opts['margin_2'] + x * w
|
142
|
+
y = ry * hh + opts['hs_2'] + h + opts['margin_2'] + y * h
|
143
|
+
return [x, y]
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def pdf_draw_box( pdf, opts )
|
148
|
+
x = @x * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
149
|
+
y = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
150
|
+
|
151
|
+
s = PDF::Writer::StrokeStyle::DEFAULT
|
152
|
+
pdf.stroke_style( s )
|
153
|
+
|
154
|
+
if @darkness
|
155
|
+
pdf.fill_color( Color::RGB::Gray )
|
156
|
+
else
|
157
|
+
pdf.fill_color( Color::RGB::White )
|
158
|
+
end
|
159
|
+
|
160
|
+
pdf.rectangle(x, y, opts['w'], opts['h']).fill_stroke
|
161
|
+
end
|
162
|
+
|
163
|
+
def pdf_draw_name(pdf, opts)
|
164
|
+
# We could also use pdf_corner(7) here
|
165
|
+
x = @x * opts['ww'] + opts['margin_2'] + opts['ws_2'] + 2
|
166
|
+
y = opts['height'] - @y
|
167
|
+
y = y * opts['hh'] + opts['margin_2'] + opts['hs_2'] + opts['h'] - 10
|
168
|
+
font_size = 8
|
169
|
+
pdf.stroke_color(Color::RGB::Black)
|
170
|
+
pdf.fill_color(Color::RGB::Black)
|
171
|
+
text = @name
|
172
|
+
while text != ''
|
173
|
+
text = pdf.add_text_wrap(x, y, opts['w'], text, font_size)
|
174
|
+
y -= font_size
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def pdf_draw( pdf, opts, idx )
|
179
|
+
pdf_draw_box( pdf, opts )
|
180
|
+
pdf_draw_name( pdf, opts )
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
|
185
|
+
|
186
|
+
class FXPage
|
187
|
+
|
188
|
+
def pdf_draw_grid(pdf, opts, w, h )
|
189
|
+
(0...w).each { |xx|
|
190
|
+
(0...h).each { |yy|
|
191
|
+
x = xx * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
192
|
+
y = yy * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
193
|
+
pdf.rectangle(x, y, opts['w'], opts['h']).stroke
|
194
|
+
}
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
def pdf_draw_mapname( pdf, opts, mapname )
|
199
|
+
return if not mapname or mapname == ''
|
200
|
+
pdf.text( mapname,
|
201
|
+
:font_size => 24,
|
202
|
+
:justification => :center
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
def pdf_draw_pagename( pdf, opts )
|
207
|
+
return if not @name or @name == ''
|
208
|
+
pdf.text( @name,
|
209
|
+
:font_size => 16,
|
210
|
+
:justification => :center
|
211
|
+
)
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
def pdf_draw(pdf, opts, mapname )
|
216
|
+
width, height = rooms_width_height
|
217
|
+
|
218
|
+
#
|
219
|
+
# Determine if better to print page in landscape mode
|
220
|
+
#
|
221
|
+
landscape = false
|
222
|
+
if landscape
|
223
|
+
pdf.rotate_axis(90.0)
|
224
|
+
pdf.translate_axis( 0, -pdf.page_width )
|
225
|
+
end
|
226
|
+
|
227
|
+
# Use times-roman as font
|
228
|
+
pdf.select_font 'Times-Roman'
|
229
|
+
pdf.stroke_color(Color::RGB::Black)
|
230
|
+
pdf.fill_color(Color::RGB::Black)
|
231
|
+
|
232
|
+
pdf_draw_mapname( pdf, opts, mapname )
|
233
|
+
pdf_draw_pagename( pdf, opts )
|
234
|
+
|
235
|
+
# For testing purposes only, draw grid of boxes
|
236
|
+
# pdf_draw_grid( pdf, opts, width, height )
|
237
|
+
|
238
|
+
@connections.each { |c| c.pdf_draw( pdf, opts ) }
|
239
|
+
@rooms.each_with_index { |r, idx| r.pdf_draw( pdf, opts, idx) }
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
|
244
|
+
class FXMap
|
245
|
+
|
246
|
+
def pdf_draw_pages( pdf, opts )
|
247
|
+
old_page = @page
|
248
|
+
@pages.each_with_index { |p, idx|
|
249
|
+
pdf.start_new_page if idx > 0
|
250
|
+
@page = idx
|
251
|
+
# For each page, we need to regenerate the pathmap so that complex
|
252
|
+
# paths will come out ok.
|
253
|
+
create_pathmap
|
254
|
+
# Now, we draw it
|
255
|
+
p.pdf_draw(pdf, opts, @name)
|
256
|
+
}
|
257
|
+
|
258
|
+
# Restore original viewing page
|
259
|
+
@page = old_page
|
260
|
+
create_pathmap
|
261
|
+
end
|
262
|
+
|
263
|
+
def pdf_export(pdffile = Dir::tmpdir + "/ifmap.pdf", printer = nil)
|
264
|
+
|
265
|
+
paper = 'LETTER'
|
266
|
+
if printer
|
267
|
+
case printer.mediasize
|
268
|
+
when FXPrinter::MEDIA_LEGAL
|
269
|
+
paper = 'LEGAL'
|
270
|
+
when FXPrinter::MEDIA_A4
|
271
|
+
paper = 'A4'
|
272
|
+
when FXPrinter::MEDIA_ENVELOPE
|
273
|
+
paper = 'ENVELOPE'
|
274
|
+
when FXPrinter::MEDIA_CUSTOM
|
275
|
+
raise "Sorry, custom paper not supported"
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
# Open a new PDF writer with paper selected
|
280
|
+
pdf = PDF::Writer.new :paper => paper
|
281
|
+
|
282
|
+
|
283
|
+
pdf_options = @options.dup
|
284
|
+
pdf_options.merge!(
|
285
|
+
{
|
286
|
+
'ww' => PDF_ROOM_WIDTH + PDF_ROOM_WS,
|
287
|
+
'hh' => PDF_ROOM_HEIGHT + PDF_ROOM_HS,
|
288
|
+
'w' => PDF_ROOM_WIDTH,
|
289
|
+
'h' => PDF_ROOM_HEIGHT,
|
290
|
+
'ws' => PDF_ROOM_WS,
|
291
|
+
'hs' => PDF_ROOM_HS,
|
292
|
+
'ws_2' => PDF_ROOM_WS / 2.0,
|
293
|
+
'hs_2' => PDF_ROOM_HS / 2.0,
|
294
|
+
'margin' => PDF_MARGIN,
|
295
|
+
'margin_2' => PDF_MARGIN / 2.0,
|
296
|
+
'width' => @width - 1,
|
297
|
+
'height' => @height - 1,
|
298
|
+
}
|
299
|
+
)
|
300
|
+
|
301
|
+
|
302
|
+
begin
|
303
|
+
# See if it is possible to pack several map sections (pages) into
|
304
|
+
# a single print page.
|
305
|
+
# pack_sections
|
306
|
+
pdf_draw_pages(pdf, pdf_options)
|
307
|
+
p "Saving pdf to '#{pdffile}'..."
|
308
|
+
pdf.save_as(pdffile)
|
309
|
+
rescue => e
|
310
|
+
p e
|
311
|
+
p e.backtrace
|
312
|
+
# raise e
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require 'IFMapper/Connection'
|
4
|
+
require 'IFMapper/Room'
|
5
|
+
|
6
|
+
class Page
|
7
|
+
attr_accessor :rooms
|
8
|
+
attr_accessor :connections
|
9
|
+
attr_accessor :name
|
10
|
+
|
11
|
+
def marshal_load(v)
|
12
|
+
@rooms = v[0]
|
13
|
+
@connections = v[1]
|
14
|
+
@name = v[2]
|
15
|
+
end
|
16
|
+
|
17
|
+
def marshal_dump
|
18
|
+
return [ @rooms, @connections, @name ]
|
19
|
+
end
|
20
|
+
|
21
|
+
#
|
22
|
+
# Return the number of rooms in width and height for this page
|
23
|
+
#
|
24
|
+
def rooms_width_height
|
25
|
+
minXY, maxXY = min_max_rooms
|
26
|
+
return [
|
27
|
+
maxXY[0] - minXY[0] + 1,
|
28
|
+
maxXY[1] - minXY[1] + 1
|
29
|
+
]
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Return the min and max coordinates of all rooms in page
|
34
|
+
#
|
35
|
+
def min_max_rooms
|
36
|
+
return [0, 0] if @rooms.empty?
|
37
|
+
|
38
|
+
minXY = [ @rooms[0].x, @rooms[0].y ]
|
39
|
+
maxXY = minXY.dup
|
40
|
+
@rooms.each { |r|
|
41
|
+
minXY[0] = r.x if r.x < minXY[0]
|
42
|
+
minXY[1] = r.y if r.y < minXY[1]
|
43
|
+
maxXY[0] = r.x if r.x > maxXY[0]
|
44
|
+
maxXY[1] = r.y if r.y > maxXY[1]
|
45
|
+
}
|
46
|
+
return [ minXY, maxXY ]
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def delete_connection(c)
|
51
|
+
a = c.roomA
|
52
|
+
if a
|
53
|
+
e = a.exits.index(c)
|
54
|
+
a[e] = nil if e
|
55
|
+
end
|
56
|
+
b = c.roomB
|
57
|
+
if b
|
58
|
+
e = b.exits.rindex(c)
|
59
|
+
b[e] = nil if e
|
60
|
+
end
|
61
|
+
@connections.delete(c)
|
62
|
+
end
|
63
|
+
|
64
|
+
def delete_connection_at( idx )
|
65
|
+
c = @connections[idx]
|
66
|
+
|
67
|
+
a = c.roomA
|
68
|
+
if a
|
69
|
+
e = a.exits.index(c)
|
70
|
+
a[e] = nil if e
|
71
|
+
end
|
72
|
+
b = c.roomB
|
73
|
+
if b
|
74
|
+
e = b.exits.rindex(c)
|
75
|
+
b[e] = nil if e
|
76
|
+
end
|
77
|
+
@connections.delete_at(idx)
|
78
|
+
end
|
79
|
+
|
80
|
+
def _new_connection(c, roomA, exitA, roomB, exitB)
|
81
|
+
exitA = roomA.exit_to(roomB) if not exitA
|
82
|
+
if not exitA
|
83
|
+
err = <<"EOF"
|
84
|
+
No exit given or guessed to connect:
|
85
|
+
Room #{roomA} (#{roomA.x}, #{roomA.y})
|
86
|
+
Room #{roomB} (#{roomB.x}, #{roomB.y})
|
87
|
+
EOF
|
88
|
+
raise err
|
89
|
+
end
|
90
|
+
|
91
|
+
if roomA[exitA]
|
92
|
+
if not @connections.include?(roomA[exitA])
|
93
|
+
raise "room exit filled but not in page"
|
94
|
+
end
|
95
|
+
raise "room exit #{exitA} for #{roomA} is filled"
|
96
|
+
end
|
97
|
+
|
98
|
+
roomA[exitA] = c
|
99
|
+
|
100
|
+
if roomB and not exitB
|
101
|
+
dx, dy = Room::DIR_TO_VECTOR[exitA]
|
102
|
+
x = roomA.x + dx
|
103
|
+
y = roomA.y + dy
|
104
|
+
if roomB.x == x and roomB.y == y
|
105
|
+
exitB = (exitA + 4) % 8
|
106
|
+
else
|
107
|
+
dx = x - roomB.x
|
108
|
+
dy = y - roomB.y
|
109
|
+
exitB = roomB.vector_to_dir(dx, dy)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
if roomB and roomB[exitB] and roomB[exitB] != c
|
114
|
+
raise "room exit #{exitB} for #{roomB} is filled"
|
115
|
+
end
|
116
|
+
roomB[exitB] = c if roomB
|
117
|
+
|
118
|
+
@connections.push( c )
|
119
|
+
return c
|
120
|
+
end
|
121
|
+
|
122
|
+
def new_connection( roomA, exitA, roomB, exitB = nil )
|
123
|
+
c = Connection.new( roomA, roomB )
|
124
|
+
_new_connection(c, roomA, exitA, roomB, exitB )
|
125
|
+
end
|
126
|
+
|
127
|
+
def delete_room_at(idx)
|
128
|
+
r = @rooms[idx]
|
129
|
+
r.exits.each { |e|
|
130
|
+
next if not e
|
131
|
+
delete_connection(e)
|
132
|
+
}
|
133
|
+
@rooms.delete_at(idx)
|
134
|
+
end
|
135
|
+
|
136
|
+
def delete_room(r)
|
137
|
+
r.exits.each { |e|
|
138
|
+
next if not e
|
139
|
+
delete_connection(e)
|
140
|
+
}
|
141
|
+
@rooms.delete(r)
|
142
|
+
end
|
143
|
+
|
144
|
+
def _new_room( r, x, y )
|
145
|
+
@rooms.push(r)
|
146
|
+
return r
|
147
|
+
end
|
148
|
+
|
149
|
+
def new_room( x, y )
|
150
|
+
r = Room.new( x, y, 'New Location' )
|
151
|
+
return _new_room(r, x, y)
|
152
|
+
end
|
153
|
+
|
154
|
+
def initialize()
|
155
|
+
@rooms = []
|
156
|
+
@connections = []
|
157
|
+
end
|
158
|
+
end
|