ifmapper 0.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|