ifmapper 1.0.8 → 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +4 -0
- data/IFMapper.gemspec +1 -1
- data/TODO.txt +0 -2
- data/docs/en/index.html +1 -1
- data/lib/IFMapper/FXMap.rb +35 -23
- data/lib/IFMapper/FXMapperWindow.rb +2 -1
- data/lib/IFMapper/PDFMapExporter_pdfwriter.rb +526 -0
- data/lib/IFMapper/PDFMapExporter_prawn.rb +528 -0
- data/lib/IFMapper/Room.rb +1 -0
- data/lib/IFMapper/TranscriptReader.rb +61 -0
- data/lib/IFMapper/locales/en/Messages.rb +13 -1
- data/lib/IFMapper/locales/es/Messages.rb +13 -2
- data/maps/Bronze.map +0 -0
- data/maps/Bureaucracy.map +0 -0
- data/maps/Byzantine.map +0 -0
- data/maps/CityOfSecrets.map +0 -0
- data/maps/Condemned.map +0 -0
- data/maps/Duel_in_the_Snow.map +0 -0
- data/maps/Eruption.map +0 -0
- data/maps/Gatoron.map +0 -0
- data/maps/Spelunker's_Quest.map +0 -0
- metadata +66 -61
- data/docs/en/start.html~ +0 -516
@@ -0,0 +1,528 @@
|
|
1
|
+
|
2
|
+
require 'tmpdir'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'prawn'
|
6
|
+
rescue LoadError => e
|
7
|
+
err = "Prawn PDF library not found. Please install it.\n"
|
8
|
+
if $rubygems
|
9
|
+
err += "You can usually do so if you do 'gem install prawn'."
|
10
|
+
else
|
11
|
+
err += "You can download it from www.rubyforge.net."
|
12
|
+
end
|
13
|
+
raise LoadError, err
|
14
|
+
end
|
15
|
+
|
16
|
+
require 'IFMapper/MapPrinting'
|
17
|
+
|
18
|
+
PDF_ZOOM = 0.5
|
19
|
+
PDF_ROOM_WIDTH = W * PDF_ZOOM
|
20
|
+
PDF_ROOM_HEIGHT = H * PDF_ZOOM
|
21
|
+
PDF_ROOM_WS = WS * PDF_ZOOM
|
22
|
+
PDF_ROOM_HS = HS * PDF_ZOOM
|
23
|
+
PDF_MARGIN = 20.0
|
24
|
+
|
25
|
+
#
|
26
|
+
# Open all the map class and add all pdf methods there
|
27
|
+
# Gotta love Ruby's flexibility to just inject in new methods.
|
28
|
+
#
|
29
|
+
class FXConnection
|
30
|
+
def _cvt_pt(p, opts)
|
31
|
+
x = (p[0] - WW / 2.0) / WW.to_f
|
32
|
+
y = (p[1] - HH / 2.0) / HH.to_f
|
33
|
+
x = x * opts['ww'] + opts['ws_2'] + opts['margin_2'] + opts['w'] / 2.0
|
34
|
+
y = (opts['height'] - y) * opts['hh'] + opts['hs_2'] + opts['margin_2'] + opts['hs']
|
35
|
+
return [x, y]
|
36
|
+
end
|
37
|
+
|
38
|
+
def pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
39
|
+
return if @dir == BOTH
|
40
|
+
|
41
|
+
pt1, d = _arrow_info( x1, y1, x2, y2, 0.5 )
|
42
|
+
|
43
|
+
pdf.stroke_color '000000'
|
44
|
+
pdf.fill_color '000000'
|
45
|
+
pdf.fill_polygon( [ pt1[0], pt1[1] ],
|
46
|
+
[ pt1[0] + d[0], pt1[1] - d[1] ],
|
47
|
+
[ pt1[0] + d[0], pt1[1] + d[1] ] )
|
48
|
+
end
|
49
|
+
|
50
|
+
def pdf_draw_complex_as_bspline( pdf, opts )
|
51
|
+
p = []
|
52
|
+
p << _cvt_pt(@pts[0], opts)
|
53
|
+
p << p[0]
|
54
|
+
p << p[0]
|
55
|
+
@pts.each { |pt|
|
56
|
+
p << _cvt_pt(pt, opts)
|
57
|
+
}
|
58
|
+
p << p[-1]
|
59
|
+
p << p[-1]
|
60
|
+
p << p[-1]
|
61
|
+
return FXSpline::bspline(p)
|
62
|
+
end
|
63
|
+
|
64
|
+
# PRE: If it's a loop exit that comes back to the same place, let's move
|
65
|
+
# it up and right
|
66
|
+
def pdf_draw_complex_as_lines( pdf, opts )
|
67
|
+
p = []
|
68
|
+
maxy = opts['height'] * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
69
|
+
@pts.each { |pt|
|
70
|
+
if loop? == true
|
71
|
+
p << [ pt[0] * PDF_ZOOM + 10, maxy - pt[1] * PDF_ZOOM + 48 ]
|
72
|
+
else
|
73
|
+
p << [ pt[0] * PDF_ZOOM, maxy - pt[1] * PDF_ZOOM ]
|
74
|
+
end
|
75
|
+
}
|
76
|
+
return p
|
77
|
+
end
|
78
|
+
|
79
|
+
def pdf_draw_door( pdf, x1, y1, x2, y2 )
|
80
|
+
v = [ (x2-x1), (y2-y1) ]
|
81
|
+
t = 10 / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
82
|
+
v = [ v[0]*t, v[1]*t ]
|
83
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
84
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
85
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
86
|
+
pdf.stroke_color '000000'
|
87
|
+
pdf.fill_color '000000'
|
88
|
+
if @type == LOCKED_DOOR
|
89
|
+
pdf.move_to(x1, y1)
|
90
|
+
pdf.line_to(x2, y2)
|
91
|
+
else
|
92
|
+
pdf.cap_style = :butt
|
93
|
+
pdf.join_style = :miter
|
94
|
+
pdf.undash
|
95
|
+
|
96
|
+
v = [ v[0] / 4, v[1] / 4]
|
97
|
+
pdf.move_to(x1 - v[0], y1 - v[1])
|
98
|
+
pdf.line_to(x1 + v[0], y1 + v[1])
|
99
|
+
pdf.line_to(x2 + v[0], y2 + v[1])
|
100
|
+
pdf.line_to(x2 - v[0], y2 - v[1])
|
101
|
+
pdf.line_to(x1 - v[0], y1 - v[1])
|
102
|
+
|
103
|
+
pdf.cap_style = :butt
|
104
|
+
pdf.join_style = :miter
|
105
|
+
pdf.undash
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def pdf_draw_complex( pdf, opts )
|
110
|
+
pdf.stroke_color '000000'
|
111
|
+
pdf.fill_color '000000'
|
112
|
+
if opts['Paths as Curves']
|
113
|
+
if @room[0] == @room[1]
|
114
|
+
dirA, dirB = dirs
|
115
|
+
if dirA == dirB
|
116
|
+
p = pdf_draw_complex_as_lines( pdf, opts )
|
117
|
+
else
|
118
|
+
p = pdf_draw_complex_as_bspline( pdf, opts )
|
119
|
+
end
|
120
|
+
else
|
121
|
+
p = pdf_draw_complex_as_bspline( pdf, opts )
|
122
|
+
end
|
123
|
+
else
|
124
|
+
p = pdf_draw_complex_as_lines( pdf, opts )
|
125
|
+
end
|
126
|
+
|
127
|
+
pdf.stroke_color '000000'
|
128
|
+
pdf.fill_color '000000'
|
129
|
+
pdf.move_to( p[0][0], p[0][1] )
|
130
|
+
p.each { |pt| pdf.line_to( pt[0], pt[1] ) }
|
131
|
+
|
132
|
+
x1, y1 = [p[0][0], p[0][1]]
|
133
|
+
x2, y2 = [p[-1][0], p[-1][1]]
|
134
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
135
|
+
|
136
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
137
|
+
t = p.size / 2
|
138
|
+
x1, y1 = [ p[t][0], p[t][1] ]
|
139
|
+
x2, y2 = [ p[t-2][0], p[t-2][1] ]
|
140
|
+
pdf_draw_door(pdf, x1, y1, x2, y2)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def pdf_draw_simple(pdf, opts)
|
145
|
+
return if not @room[1] # PDF does not print unfinished complex connections
|
146
|
+
|
147
|
+
dir = @room[0].exits.index(self)
|
148
|
+
x1, y1 = @room[0].pdf_corner(opts, self, dir)
|
149
|
+
x2, y2 = @room[1].pdf_corner(opts, self)
|
150
|
+
pdf.stroke_color '000000'
|
151
|
+
pdf.fill_color '000000'
|
152
|
+
pdf.move_to(x1, y1)
|
153
|
+
pdf.line_to(x2, y2)
|
154
|
+
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
155
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
156
|
+
pdf_draw_door(pdf, x1, y1, x2, y2)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# Draw the connection text next to the arrow ('I', 'O', etc)
|
162
|
+
#
|
163
|
+
def pdf_draw_text(pdf, x, y, dir, text, arrow)
|
164
|
+
if dir == 7 or dir < 6 and dir != 1
|
165
|
+
if arrow and (dir == 0 or dir == 4)
|
166
|
+
x += 5
|
167
|
+
end
|
168
|
+
x += 2.5
|
169
|
+
elsif dir == 6 or dir == 1
|
170
|
+
x -= 7.5
|
171
|
+
end
|
172
|
+
|
173
|
+
if dir > 5 or dir < 4
|
174
|
+
if arrow and (dir == 6 or dir == 2)
|
175
|
+
y += 5
|
176
|
+
end
|
177
|
+
y += 2.5
|
178
|
+
elsif dir == 4 or dir == 5
|
179
|
+
y -= 7.5
|
180
|
+
end
|
181
|
+
|
182
|
+
font_size = 8
|
183
|
+
pdf.text_box text, :at => [x, y], :size => font_size
|
184
|
+
end
|
185
|
+
|
186
|
+
def pdf_draw_exit_text(pdf, opts)
|
187
|
+
|
188
|
+
if @exitText[0] != 0
|
189
|
+
dir = @room[0].exits.index(self)
|
190
|
+
x, y = @room[0].pdf_corner(opts, self, dir)
|
191
|
+
pdf.move_to(x, y)
|
192
|
+
pdf_draw_text( pdf, x, y+4, dir,
|
193
|
+
EXIT_TEXT[@exitText[0]], @dir == BtoA)
|
194
|
+
end
|
195
|
+
|
196
|
+
if @exitText[1] != 0
|
197
|
+
dir = @room[1].exits.rindex(self)
|
198
|
+
x, y = @room[1].pdf_corner(opts, self, dir)
|
199
|
+
pdf_draw_text( pdf, x, y+4, dir,
|
200
|
+
EXIT_TEXT[@exitText[1]], @dir == AtoB)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def pdf_draw(pdf, opts)
|
205
|
+
pdf_draw_exit_text(pdf, opts)
|
206
|
+
if @type == SPECIAL
|
207
|
+
pdf.dash 4
|
208
|
+
else
|
209
|
+
pdf.cap_style = :butt
|
210
|
+
pdf.join_style = :miter
|
211
|
+
pdf.undash
|
212
|
+
end
|
213
|
+
pdf.stroke_color '000000'
|
214
|
+
pdf.fill_color '000000'
|
215
|
+
if @pts.size > 0
|
216
|
+
pdf_draw_complex(pdf, opts)
|
217
|
+
else
|
218
|
+
pdf_draw_simple(pdf, opts)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
class FXRoom
|
225
|
+
def pdf_corner( opts, c, idx = nil )
|
226
|
+
x, y = _corner(c, idx)
|
227
|
+
y = -y
|
228
|
+
|
229
|
+
ww = opts['ww']
|
230
|
+
hh = opts['hh']
|
231
|
+
w = opts['w']
|
232
|
+
h = opts['h']
|
233
|
+
|
234
|
+
ry = opts['height'] - @y
|
235
|
+
x = @x * ww + opts['ws_2'] + opts['margin_2'] + x * w
|
236
|
+
y = ry * hh + opts['hs_2'] + h + opts['margin_2'] + y * h
|
237
|
+
return [x, y]
|
238
|
+
end
|
239
|
+
|
240
|
+
|
241
|
+
def pdf_draw_box( pdf, opts, idx, pdflocationnos )
|
242
|
+
x = @x * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
243
|
+
y = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
244
|
+
|
245
|
+
pdf.cap_style = :butt
|
246
|
+
pdf.join_style = :miter
|
247
|
+
pdf.line_width 1
|
248
|
+
|
249
|
+
if @darkness
|
250
|
+
pdf.fill_color '808080'
|
251
|
+
pdf.stroke_color '000000'
|
252
|
+
else
|
253
|
+
pdf.fill_color 'ffffff'
|
254
|
+
pdf.stroke_color '000000'
|
255
|
+
end
|
256
|
+
|
257
|
+
pdf.stroke_rectangle [x, y], opts['w'], -opts['h']
|
258
|
+
|
259
|
+
if pdflocationnos == 1
|
260
|
+
# PRE: Draw a rectangle for the location number
|
261
|
+
pdf.stroke_rectangle( [x+opts['w']-opts['w']/4, y],
|
262
|
+
opts['w']/4, -opts['h']/4 )
|
263
|
+
|
264
|
+
# PRE: Pad out the number so it is three chars long
|
265
|
+
locationno = (idx+1).to_s
|
266
|
+
if (idx+1) < 10
|
267
|
+
locationno = ' '+locationno
|
268
|
+
elsif (idx+1) < 100
|
269
|
+
locationno = ' '+locationno
|
270
|
+
end
|
271
|
+
|
272
|
+
# PRE: Write the location number
|
273
|
+
pdf.stroke_color '000000'
|
274
|
+
pdf.fill_color '000000'
|
275
|
+
|
276
|
+
pdf.text_box locationno,
|
277
|
+
:at => [(x+((opts['w']/4)*3)+2), y+7], :size => 8
|
278
|
+
end
|
279
|
+
|
280
|
+
end
|
281
|
+
|
282
|
+
def pdf_draw_text( pdf, opts, x, y, text, font_size, pdflocationnos )
|
283
|
+
miny = (opts['height'] - @y) * opts['hh'] + opts['hs_2'] +
|
284
|
+
opts['margin_2']
|
285
|
+
pdf.text_box text, :at => [x, y+6], :size => font_size,
|
286
|
+
:width => opts['w'], :height => opts['h'], :valign => :top,
|
287
|
+
:align => :left, :overflow => :shrink_to_fit
|
288
|
+
return [x, y]
|
289
|
+
end
|
290
|
+
|
291
|
+
def pdf_draw_objects(pdf, opts, x, y, pdflocationnos)
|
292
|
+
font_size = 6
|
293
|
+
objs = @objects.split("\n")
|
294
|
+
objs = objs.join(', ')
|
295
|
+
return pdf_draw_text( pdf, opts, x, y-font_size,
|
296
|
+
objs, font_size, pdflocationnos )
|
297
|
+
end
|
298
|
+
|
299
|
+
def pdf_draw_name(pdf, opts, pdflocationnos)
|
300
|
+
# We could also use pdf_corner(7) here
|
301
|
+
x = @x * opts['ww'] + opts['margin_2'] + opts['ws_2'] + 2
|
302
|
+
y = opts['height'] - @y
|
303
|
+
font_size = 8
|
304
|
+
y = y * opts['hh'] + opts['margin_2'] + opts['hs_2'] + opts['h'] -
|
305
|
+
(font_size + 2)
|
306
|
+
pdf.stroke_color '000000'
|
307
|
+
pdf.fill_color '000000'
|
308
|
+
return pdf_draw_text( pdf, opts, x, y, @name, font_size, pdflocationnos )
|
309
|
+
end
|
310
|
+
|
311
|
+
# PRE: Send through the index so we can print the location number
|
312
|
+
# along with boolean value indicating whether the user wants them
|
313
|
+
def pdf_draw( pdf, opts, idx, pdflocationnos )
|
314
|
+
pdf_draw_box( pdf, opts, idx, pdflocationnos )
|
315
|
+
x, y = pdf_draw_name( pdf, opts, pdflocationnos )
|
316
|
+
pdf_draw_objects(pdf, opts, x, y, pdflocationnos)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
|
321
|
+
|
322
|
+
class FXSection
|
323
|
+
|
324
|
+
def pdf_draw_grid(pdf, opts, w, h )
|
325
|
+
(0...w).each { |xx|
|
326
|
+
(0...h).each { |yy|
|
327
|
+
x = xx * opts['ww'] + opts['ws_2'] + opts['margin_2']
|
328
|
+
y = yy * opts['hh'] + opts['hs_2'] + opts['margin_2']
|
329
|
+
pdf.rectangle([x, y], opts['w'], opts['h'])
|
330
|
+
}
|
331
|
+
}
|
332
|
+
end
|
333
|
+
|
334
|
+
|
335
|
+
def pdf_draw_section_name( pdf, opts, px, py )
|
336
|
+
return if not @name or @name == ''
|
337
|
+
xymin, xymax = min_max_rooms
|
338
|
+
text = @name
|
339
|
+
text += " (#{px}, #{py})" if px > 0 or py > 0
|
340
|
+
y = (opts['height']) * opts['hh'] + 16
|
341
|
+
w = xymax[0]
|
342
|
+
w = opts['width'] if w > opts['width']
|
343
|
+
x = (w + 2) * opts['ww'] / 2 - text.size / 2 * 16
|
344
|
+
x = 0 if x < 0
|
345
|
+
pdf.text_box( text, :at => [x,y], :font_size => 16 )
|
346
|
+
end
|
347
|
+
|
348
|
+
|
349
|
+
def pdf_draw(pdf, opts, mapname, pdflocationnos )
|
350
|
+
|
351
|
+
|
352
|
+
w, h = rooms_width_height
|
353
|
+
x, y = [0, 0]
|
354
|
+
|
355
|
+
loop do
|
356
|
+
|
357
|
+
pdf.save_graphics_state
|
358
|
+
|
359
|
+
if rotate
|
360
|
+
pdf.rotate 90.0
|
361
|
+
pdf.translate( 0, -pdf.margin_box.height )
|
362
|
+
end
|
363
|
+
|
364
|
+
# Move section to its position in page
|
365
|
+
tx1, ty1 = [@xoff * opts['ww'], @yoff * -opts['hh']]
|
366
|
+
pdf.translate( tx1, ty1 )
|
367
|
+
|
368
|
+
# Use times-roman as font
|
369
|
+
pdf.font 'Times-Roman'
|
370
|
+
pdf.stroke_color '000000'
|
371
|
+
|
372
|
+
pdf_draw_section_name( pdf, opts, x, y )
|
373
|
+
|
374
|
+
xymin, = min_max_rooms
|
375
|
+
|
376
|
+
# Move rooms, so that we don't print empty areas
|
377
|
+
tx2 = -(xymin[0]) * opts['ww'] - x * opts['ww']
|
378
|
+
ty2 = (xymin[1]) * opts['hh'] - 60 + (y - (y > 0? 1 : 0)) * opts['hh']
|
379
|
+
pdf.translate( tx2, ty2 )
|
380
|
+
|
381
|
+
|
382
|
+
# For testing purposes only, draw grid of boxes
|
383
|
+
# pdf_draw_grid( pdf, opts, w, h )
|
384
|
+
@connections.each { |c|
|
385
|
+
a = c.roomA
|
386
|
+
b = c.roomB
|
387
|
+
next if a.y < y and b and b.y < y
|
388
|
+
c.pdf_draw( pdf, opts )
|
389
|
+
}
|
390
|
+
@rooms.each_with_index { |r, idx|
|
391
|
+
next if r.y < y
|
392
|
+
r.pdf_draw( pdf, opts, idx, pdflocationnos)
|
393
|
+
}
|
394
|
+
|
395
|
+
# Reset axis
|
396
|
+
pdf.translate(-tx2, -ty2)
|
397
|
+
pdf.translate(-tx1, -ty1)
|
398
|
+
|
399
|
+
xi = opts['width']
|
400
|
+
yi = opts['height']
|
401
|
+
if rotate
|
402
|
+
xi = (pdf.margin_box.height / opts['ww']).to_i - 1
|
403
|
+
yi = (pdf.margin_box.width / opts['hh']).to_i - 1
|
404
|
+
end
|
405
|
+
|
406
|
+
x += xi
|
407
|
+
if x >= w
|
408
|
+
x = 0
|
409
|
+
y += yi
|
410
|
+
break if y >= h
|
411
|
+
end
|
412
|
+
|
413
|
+
if rotate
|
414
|
+
pdf.rotate(-90.0)
|
415
|
+
pdf.translate( 0, pdf.page_height )
|
416
|
+
end
|
417
|
+
|
418
|
+
pdf.restore_graphics_state
|
419
|
+
|
420
|
+
# We could not fit all rooms in page. Start new page
|
421
|
+
pdf.start_new_page
|
422
|
+
end
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
class FXMap
|
428
|
+
|
429
|
+
attr_accessor :pdfpapersize
|
430
|
+
# boolean value indicating whether the user wants to see location nos
|
431
|
+
attr_accessor :pdflocationnos
|
432
|
+
|
433
|
+
def pdf_draw_mapname( pdf, opts )
|
434
|
+
return if not @name or @name == ''
|
435
|
+
pdf.text( @name,
|
436
|
+
:font_size => 24,
|
437
|
+
:justification => :center
|
438
|
+
)
|
439
|
+
end
|
440
|
+
|
441
|
+
def pdf_draw_sections( pdf, opts )
|
442
|
+
old_section = @section
|
443
|
+
page = -1
|
444
|
+
@sections.each_with_index { |sect, idx|
|
445
|
+
if page != sect.page
|
446
|
+
page = sect.page
|
447
|
+
pdf.start_new_page if page > 1
|
448
|
+
pdf_draw_mapname( pdf, opts )
|
449
|
+
end
|
450
|
+
@section = idx
|
451
|
+
# For each page, we need to regenerate the pathmap so that complex
|
452
|
+
# paths will come out ok.
|
453
|
+
create_pathmap
|
454
|
+
# Now, we draw it
|
455
|
+
sect.pdf_draw(pdf, opts, @name, pdflocationnos)
|
456
|
+
}
|
457
|
+
|
458
|
+
# Restore original viewing page
|
459
|
+
@section = old_section
|
460
|
+
create_pathmap
|
461
|
+
end
|
462
|
+
|
463
|
+
|
464
|
+
def pdf_export(pdffile = Dir::tmpdir + "/ifmap.pdf", printer = nil)
|
465
|
+
|
466
|
+
# PRE: Let's set the PDF paper size to user's choice
|
467
|
+
paper = BOX_PDF_PAGE_SIZE_TEXT[pdfpapersize]
|
468
|
+
if printer
|
469
|
+
case printer.mediasize
|
470
|
+
when FXPrinter::MEDIA_LETTER
|
471
|
+
paper = 'LETTER'
|
472
|
+
when FXPrinter::MEDIA_LEGAL
|
473
|
+
paper = 'LEGAL'
|
474
|
+
when FXPrinter::MEDIA_A4
|
475
|
+
paper = 'A4'
|
476
|
+
when FXPrinter::MEDIA_ENVELOPE
|
477
|
+
paper = 'ENVELOPE'
|
478
|
+
when FXPrinter::MEDIA_CUSTOM
|
479
|
+
raise "Sorry, custom paper not supported"
|
480
|
+
end
|
481
|
+
end
|
482
|
+
|
483
|
+
# Open a new PDF writer with paper selected
|
484
|
+
# PRE: Let's also set the paper orientation based on user selection
|
485
|
+
|
486
|
+
pdf = Prawn::Document.new :page_size => paper
|
487
|
+
|
488
|
+
pdf_options = @options.dup
|
489
|
+
|
490
|
+
ww = PDF_ROOM_WIDTH + PDF_ROOM_WS
|
491
|
+
hh = PDF_ROOM_HEIGHT + PDF_ROOM_HS
|
492
|
+
|
493
|
+
pdf_options.merge!(
|
494
|
+
{
|
495
|
+
'ww' => ww,
|
496
|
+
'hh' => hh,
|
497
|
+
'w' => PDF_ROOM_WIDTH,
|
498
|
+
'h' => PDF_ROOM_HEIGHT,
|
499
|
+
'ws' => PDF_ROOM_WS,
|
500
|
+
'hs' => PDF_ROOM_HS,
|
501
|
+
'ws_2' => PDF_ROOM_WS / 2.0,
|
502
|
+
'hs_2' => PDF_ROOM_HS / 2.0,
|
503
|
+
'margin' => PDF_MARGIN,
|
504
|
+
'margin_2' => PDF_MARGIN / 2.0,
|
505
|
+
'width' => (pdf.margin_box.width / ww).to_i - 1,
|
506
|
+
'height' => (pdf.margin_box.height / hh).to_i - 1,
|
507
|
+
}
|
508
|
+
)
|
509
|
+
|
510
|
+
|
511
|
+
begin
|
512
|
+
# See if it is possible to pack several map sections (sections) into
|
513
|
+
# a single print page.
|
514
|
+
num = pack_sections( pdf_options['width'] + 2,
|
515
|
+
pdf_options['height'] + 2 )
|
516
|
+
pdf_draw_sections(pdf, pdf_options)
|
517
|
+
if pdffile !~ /\.pdf$/
|
518
|
+
pdffile << ".pdf"
|
519
|
+
end
|
520
|
+
status "Exporting PDF file '#{pdffile}'"
|
521
|
+
pdf.render_file pdffile
|
522
|
+
rescue => e
|
523
|
+
p e
|
524
|
+
p e.backtrace
|
525
|
+
raise e
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
data/lib/IFMapper/Room.rb
CHANGED
@@ -140,6 +140,7 @@ class TranscriptReader
|
|
140
140
|
SHORTNAME_MOONMIST = 2
|
141
141
|
SHORTNAME_WITNESS = 3
|
142
142
|
SHORTNAME_ADRIFT = 4
|
143
|
+
SHORTNAME_ALL_CAPS = 5
|
143
144
|
|
144
145
|
attr_reader :shortName
|
145
146
|
attr_accessor :identify, :map
|
@@ -843,6 +844,8 @@ class TranscriptReader
|
|
843
844
|
|
844
845
|
def room_name(line)
|
845
846
|
case @shortName
|
847
|
+
when SHORTNAME_ALL_CAPS
|
848
|
+
return room_name_all_caps(line)
|
846
849
|
when SHORTNAME_CAPITALIZED
|
847
850
|
return room_name_classic(line, false)
|
848
851
|
when SHORTNAME_MOONMIST
|
@@ -952,6 +955,64 @@ class TranscriptReader
|
|
952
955
|
return line
|
953
956
|
end
|
954
957
|
|
958
|
+
#
|
959
|
+
# Determine if line corresponds to a room name
|
960
|
+
#
|
961
|
+
def room_name_all_caps(line)
|
962
|
+
# Check if user/game has created a room with that name already
|
963
|
+
return line if find_room(line, nil)
|
964
|
+
|
965
|
+
# We have a room if we match darkness
|
966
|
+
return line if line =~ DARKNESS
|
967
|
+
|
968
|
+
# Remove unwanted stuff line (on the bed)
|
969
|
+
line.sub!(NAME_REMOVE, '')
|
970
|
+
|
971
|
+
# Check if user/game has created a room with that name already
|
972
|
+
return line if find_room(line, nil)
|
973
|
+
|
974
|
+
# Remove periods from salutations
|
975
|
+
line.sub!(SALUTATIONS, '\1')
|
976
|
+
|
977
|
+
# quick check for invalid format
|
978
|
+
return false if line =~ NAME_INVALID
|
979
|
+
|
980
|
+
# Qucik check for word characters
|
981
|
+
return false unless line =~ /\w/
|
982
|
+
|
983
|
+
# Check if we start line with uncapitalized words or symbols
|
984
|
+
return false if line =~ /^[ a-z\/\\\-\(\)']/
|
985
|
+
|
986
|
+
# Check if line holds only capitalized words or several spaces together
|
987
|
+
# or a quote or a 1) line. If so, not a room.
|
988
|
+
return false if line =~ /^[a-z\d,\.\/\-"'\s]+$/ or line =~ /\s\s/ or
|
989
|
+
line =~ /^".*"$/ or line =~ /^"[^"]+$/ or line =~ /^\d+\)/
|
990
|
+
|
991
|
+
# Check word count (if too many, not a room)
|
992
|
+
words = line.split(' ')
|
993
|
+
return false if words.size > NAME_MAXWORDS
|
994
|
+
|
995
|
+
|
996
|
+
# If not, check all words of 4 chars or more are capitalized
|
997
|
+
# and that there are no 3 or more short letter words together
|
998
|
+
# (which means a diagram)
|
999
|
+
num = 0
|
1000
|
+
words.each { |w|
|
1001
|
+
if w.size <= 2
|
1002
|
+
num += 1
|
1003
|
+
return false if num > 2
|
1004
|
+
else
|
1005
|
+
num = 0
|
1006
|
+
end
|
1007
|
+
}
|
1008
|
+
|
1009
|
+
# Restore period to salutations
|
1010
|
+
line.sub!(/\b#{SALUT}\b/, '\1.')
|
1011
|
+
|
1012
|
+
# Okay, it is a room.
|
1013
|
+
return line
|
1014
|
+
end
|
1015
|
+
|
955
1016
|
#
|
956
1017
|
# Create a new room
|
957
1018
|
#
|
@@ -133,6 +133,8 @@ Commands always begin with a > prompt.",
|
|
133
133
|
names where all words of 5 or more characters are capitalized).
|
134
134
|
However, commands do not begin with any type of prompt but start
|
135
135
|
with a lowercase word without any margin.",
|
136
|
+
"ALL CAPS mode is like Classic Mode but expects locations to be
|
137
|
+
spelled all in caps."
|
136
138
|
]
|
137
139
|
|
138
140
|
|
@@ -171,6 +173,12 @@ Front of Mall
|
|
171
173
|
spot of pavement is too narrow a place for them to stall. It is just
|
172
174
|
right for bicycles and motorbikes such as yours.
|
173
175
|
",
|
176
|
+
"
|
177
|
+
> look
|
178
|
+
WEST OF HOUSE
|
179
|
+
You are standing in an open field west of a white house, with a boarded
|
180
|
+
front door.
|
181
|
+
"
|
174
182
|
]
|
175
183
|
|
176
184
|
TRANSCRIPT_LOCATION2_TEXT = [
|
@@ -189,6 +197,9 @@ Women's change room
|
|
189
197
|
"
|
190
198
|
Front of Mall
|
191
199
|
",
|
200
|
+
"
|
201
|
+
WEST OF HALL
|
202
|
+
"
|
192
203
|
]
|
193
204
|
|
194
205
|
|
@@ -203,6 +214,7 @@ TRANSCRIPT_SHORTNAME_TYPE = [
|
|
203
214
|
'Moonmist',
|
204
215
|
'Witness',
|
205
216
|
'ADRIFT',
|
217
|
+
'ALL CAPS'
|
206
218
|
]
|
207
219
|
|
208
220
|
############ Window Titles
|
@@ -227,7 +239,7 @@ MSG_COMPLEX_CONNECTION_STOPPED = 'Complex connection interrupted.'
|
|
227
239
|
MSG_COMPLEX_CONNECTION_DONE = 'Complex connection done.'
|
228
240
|
|
229
241
|
MSG_CLICK_TO_SELECT_AND_MOVE = 'Click to select and move. Double click to edit.'
|
230
|
-
|
242
|
+
MSG_CLICK_TOGGLE_ONE_WAY_CONNECTION = 'Click to toggle one way connection.'
|
231
243
|
MSG_CLICK_CREATE_ROOM = 'Click to create new room.'
|
232
244
|
MSG_CLICK_CREATE_LINK = 'Click to create new connection.'
|
233
245
|
|
@@ -142,6 +142,8 @@ Los comandos siempre comienzan tras un >.",
|
|
142
142
|
"Modo ADRIFT espera las localidades como en el modo Clásico
|
143
143
|
(encabezados de palabras de 5 o más letras en mayúsculas).
|
144
144
|
Los comandos comienzan sólo con una palabra en minúscula sin margen.",
|
145
|
+
"Modo TODO MAYUSCULAS es como el modo Classic pero espera que los encabezados
|
146
|
+
de la localidad esten todo en mayusculas."
|
145
147
|
]
|
146
148
|
|
147
149
|
|
@@ -180,6 +182,11 @@ Entrada del Shopping
|
|
180
182
|
del pavimento es demasiado angosto para que estacionen. Es apenas
|
181
183
|
apropiado para bicicletas y motocicletas como la tuya.
|
182
184
|
",
|
185
|
+
"> mira
|
186
|
+
AL OESTE DE LA CASA
|
187
|
+
Estás parado en un campo abierto al oeste de una casa blanca, con una
|
188
|
+
puerta clausurada.
|
189
|
+
"
|
183
190
|
]
|
184
191
|
|
185
192
|
TRANSCRIPT_LOCATION2_TEXT = [
|
@@ -198,6 +205,9 @@ Vestidor de mujeres
|
|
198
205
|
"
|
199
206
|
Entrada del Shopping
|
200
207
|
",
|
208
|
+
"
|
209
|
+
AL OESTE DE LA CASA
|
210
|
+
"
|
201
211
|
]
|
202
212
|
|
203
213
|
|
@@ -212,6 +222,7 @@ TRANSCRIPT_SHORTNAME_TYPE = [
|
|
212
222
|
'Moonmist',
|
213
223
|
'Witness',
|
214
224
|
'ADRIFT',
|
225
|
+
'Todo Mayúsculas'
|
215
226
|
]
|
216
227
|
|
217
228
|
############ Títulos de Ventanas
|
@@ -233,7 +244,7 @@ MSG_COMPLEX_CONNECTION_STOPPED = 'Creación de la conexión compleja interrumpid
|
|
233
244
|
MSG_COMPLEX_CONNECTION_DONE = 'Conexión compleja completada.'
|
234
245
|
|
235
246
|
MSG_CLICK_TO_SELECT_AND_MOVE = 'Cliquée para seleccionar y mover. Cliquée dos veces para editar.'
|
236
|
-
|
247
|
+
MSG_CLICK_TOGGLE_ONE_WAY_CONNECTION = 'Cliquée para intercambiar conexión de un solo lado.'
|
237
248
|
MSG_CLICK_CREATE_ROOM = 'Cliquée para crear una nueva localidad.'
|
238
249
|
MSG_CLICK_CREATE_LINK = 'Cliquée para crear una nueva conexión.'
|
239
250
|
|
@@ -354,7 +365,7 @@ BOX_OBJECTS = 'Objetos: '
|
|
354
365
|
BOX_DARKNESS = 'Oscuridad'
|
355
366
|
BOX_TASKS = 'Tareas: '
|
356
367
|
BOX_DESCRIPTION = 'Descripción: '
|
357
|
-
BOX_COMMENTS = '
|
368
|
+
BOX_COMMENTS = 'Comentarios: '
|
358
369
|
|
359
370
|
BOX_CONNECTION_TYPE = 'Tipo de Conexión: '
|
360
371
|
BOX_CONNECTION_TYPE_TEXT = [
|