ifmapper 0.8.1 → 0.8.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 +58 -3
- data/IFMapper.gemspec +1 -1
- data/lib/IFMapper/Connection.rb +10 -0
- data/lib/IFMapper/FXConnection.rb +19 -3
- data/lib/IFMapper/FXMap.rb +27 -12
- data/lib/IFMapper/FXMapDialogBox.rb +1 -1
- data/lib/IFMapper/FXMapperWindow.rb +32 -11
- data/lib/IFMapper/FXRoom.rb +13 -1
- data/lib/IFMapper/FXSpline.rb +1 -1
- data/lib/IFMapper/IFMReader.rb +1 -2
- data/lib/IFMapper/PDFMapExporter.rb +15 -0
- data/lib/IFMapper/Room.rb +23 -6
- data/lib/IFMapper/TranscriptReader.rb +212 -82
- metadata +9 -9
data/HISTORY.txt
CHANGED
@@ -1,9 +1,64 @@
|
|
1
1
|
|
2
|
-
v0.8.
|
3
|
-
|
2
|
+
v0.8.5 - This is mainly a bug fix release.
|
3
|
+
|
4
|
+
- Improvements to the automapper:
|
5
|
+
* Now it uses much, much less memory as the automapper database
|
6
|
+
will now use the actual map database. This is mainly a departure
|
7
|
+
from the original Perl code.
|
8
|
+
* Now it will properly recognize rooms that were created manually.
|
9
|
+
This allows you to start the automapper with an already created
|
10
|
+
map and also work around any rooms that the automapper does not
|
11
|
+
automatically recognize.
|
12
|
+
* Cut/Copy/Paste rooms will also internally copy their descriptions,
|
13
|
+
so the automapper will not get confused.
|
14
|
+
* Adding objects now checks if the object was already typed in
|
15
|
+
manually.
|
16
|
+
* Fixed a bug with in/out/down/up exits not recognizing if the exit
|
17
|
+
was already drawn in the room, resulting in two identical exits.
|
18
|
+
* Now saving/loading a map that has been automapped will also save its
|
19
|
+
descriptions. This allows you to keep automapping a game easily
|
20
|
+
in different sessions.
|
21
|
+
* Restore/Restart/Unscript was not working appropiately.
|
22
|
+
It should have allowed you to "teleport" to any new location, yet
|
23
|
+
it was creating incorrect links.
|
24
|
+
* There's now better handling of rooms gone dark (previously, they
|
25
|
+
were treated as a separate location and multiple dark rooms
|
26
|
+
would create links to a single dark room)
|
27
|
+
|
28
|
+
- .map save format now is smaller, as some useless data was getting
|
29
|
+
saved, which we now skip. Note, however, that when automapping
|
30
|
+
.map size is bigger, as room descriptions get also stored now.
|
31
|
+
|
32
|
+
- Fixed a minor display bug when room name would take 4 rows and
|
33
|
+
objects would not fit in box.
|
34
|
+
|
35
|
+
- Added some new (possibly incomplete) maps, that I did while
|
36
|
+
testing the stuff. All done with automapper:
|
37
|
+
Deadline, Dutch Dapper, Blue Doors, Inhumane, Not Just an
|
38
|
+
Ordinary Ballerina.
|
39
|
+
|
40
|
+
- Map resizing was always complaining about rooms being deleted.
|
41
|
+
Fixed.
|
42
|
+
|
43
|
+
- Fixed a nasty crashing bug that would happen if trying to load
|
44
|
+
an IFM file with no windows open.
|
45
|
+
|
46
|
+
- Fixed a nasty crashing bug when pasting and then immediately
|
47
|
+
selecting pasted rooms, as the rooms were not added to the
|
48
|
+
pathmap.
|
49
|
+
|
50
|
+
- Complex doors that are locked are now drawn with a crossed line
|
51
|
+
along the middle.
|
52
|
+
|
53
|
+
- Complex paths drawn as bsplines are now drawn with a tad less
|
54
|
+
quality to improve drawing speed.
|
55
|
+
|
56
|
+
v0.8.1 - Just some fixes to the automapper, as it was failing on some
|
57
|
+
relatively simple games.
|
4
58
|
|
5
59
|
Automapper was not matching rooms with periods in them. This was
|
6
|
-
causing problems with games that had rooms like "Mr. Hellman's
|
60
|
+
causing problems with games that had rooms like "Mr. Hellman's
|
61
|
+
Bedroom".
|
7
62
|
|
8
63
|
Improved the handling of multiple directional commands. A command
|
9
64
|
like: 'n, e, w' is now handled properly.
|
data/IFMapper.gemspec
CHANGED
@@ -2,7 +2,7 @@ require "rubygems"
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |spec|
|
4
4
|
spec.name = "ifmapper"
|
5
|
-
spec.version = '0.8.
|
5
|
+
spec.version = '0.8.5'
|
6
6
|
spec.author = "Gonzalo Garramuno"
|
7
7
|
spec.email = 'ggarram@advance.dsl.com.ar'
|
8
8
|
spec.homepage = 'http://www.rubyforge.org/projects/ifmapper/'
|
data/lib/IFMapper/Connection.rb
CHANGED
@@ -28,6 +28,16 @@ class Connection
|
|
28
28
|
'O'
|
29
29
|
]
|
30
30
|
|
31
|
+
|
32
|
+
def marshal_load(vars)
|
33
|
+
@type, @dir, @roomA, @roomB,
|
34
|
+
@exitAtext, @exitBtext = vars
|
35
|
+
end
|
36
|
+
|
37
|
+
def marshal_dump
|
38
|
+
[ @type, @dir, @roomA, @roomB, @exitAtext, @exitBtext ]
|
39
|
+
end
|
40
|
+
|
31
41
|
def initialize( roomA, roomB, dir = BOTH, type = FREE )
|
32
42
|
@roomA = roomA
|
33
43
|
@roomB = roomB
|
@@ -46,13 +46,13 @@ class FXConnection < Connection
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def marshal_load(vars)
|
49
|
-
@selected, @type, @dir, @roomA, @roomB,
|
50
|
-
@exitAtext, @exitBtext = vars
|
51
49
|
@pts = @gpts = []
|
50
|
+
@selected = vars.shift
|
51
|
+
super(vars)
|
52
52
|
end
|
53
53
|
|
54
54
|
def marshal_dump
|
55
|
-
[ @selected
|
55
|
+
[ @selected ] + super
|
56
56
|
end
|
57
57
|
|
58
58
|
#
|
@@ -218,6 +218,20 @@ class FXConnection < Connection
|
|
218
218
|
x1, y1 = [p[0].x, p[0].y]
|
219
219
|
x2, y2 = [p[-1].x, p[-1].y]
|
220
220
|
draw_arrow(dc, zoom, x1, y1, x2, y2)
|
221
|
+
|
222
|
+
if @type == LOCKED_DOOR
|
223
|
+
t = p.size / 2
|
224
|
+
x1, y1 = [ p[t].x, p[t].y ]
|
225
|
+
x2, y2 = [ p[t-2].x, p[t-2].y ]
|
226
|
+
|
227
|
+
v = [ (x2-x1), (y2-y1) ]
|
228
|
+
t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
229
|
+
v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
|
230
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
231
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
232
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
233
|
+
dc.drawLine(x1, y1, x2, y2)
|
234
|
+
end
|
221
235
|
end
|
222
236
|
|
223
237
|
#
|
@@ -233,6 +247,8 @@ class FXConnection < Connection
|
|
233
247
|
draw_arrow(dc, zoom, x1, y1, x2, y2)
|
234
248
|
if @type == LOCKED_DOOR
|
235
249
|
v = [ (x2-x1)*0.25, (y2-y1)*0.25 ]
|
250
|
+
t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
251
|
+
v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
|
236
252
|
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
237
253
|
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
238
254
|
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
data/lib/IFMapper/FXMap.rb
CHANGED
@@ -366,7 +366,6 @@ class FXMap < Map
|
|
366
366
|
def new_room(x, y)
|
367
367
|
@modified = true
|
368
368
|
r = @sections[@section].new_room(x, y)
|
369
|
-
@automap.add(r) if @automap
|
370
369
|
return r
|
371
370
|
end
|
372
371
|
|
@@ -786,12 +785,16 @@ class FXMap < Map
|
|
786
785
|
#
|
787
786
|
# Based on mouse position on canvas, create a tooltip
|
788
787
|
#
|
789
|
-
def
|
790
|
-
|
791
|
-
|
792
|
-
|
788
|
+
def tooltip_cb(sender, id, ptr)
|
789
|
+
if @tooltip_msg != ''
|
790
|
+
sender.text = @tooltip_msg.to_s
|
791
|
+
sender.show
|
792
|
+
else
|
793
|
+
sender.hide
|
794
|
+
end
|
793
795
|
end
|
794
796
|
|
797
|
+
|
795
798
|
#
|
796
799
|
# Show some help status in status line based on cursor position
|
797
800
|
#
|
@@ -804,10 +807,12 @@ class FXMap < Map
|
|
804
807
|
return
|
805
808
|
end
|
806
809
|
|
810
|
+
@tooltip_msg = ''
|
807
811
|
sel = to_object(x, y)
|
808
812
|
if sel
|
809
813
|
@canvas.defaultCursor = @@cursor_arrow
|
810
814
|
if sel.kind_of?(Room)
|
815
|
+
@tooltip_msg = sel.name
|
811
816
|
status "Click to select and move. Double click to edit room."
|
812
817
|
elsif sel.kind_of?(Connection)
|
813
818
|
status "Click to change direction of connection."
|
@@ -890,6 +895,7 @@ class FXMap < Map
|
|
890
895
|
|
891
896
|
draw
|
892
897
|
dc = FXDCWindow.new(@canvas)
|
898
|
+
dc.function = BLT_NOT_SRC_XOR_DST
|
893
899
|
dc.drawRectangle(x, y, w * @zoom, h * @zoom)
|
894
900
|
dc.end
|
895
901
|
end
|
@@ -909,6 +915,7 @@ class FXMap < Map
|
|
909
915
|
@dx = dx
|
910
916
|
@dy = dy
|
911
917
|
@scrollwindow.setPosition(pos[0], pos[1])
|
918
|
+
@canvas.repaint
|
912
919
|
end
|
913
920
|
elsif @mouseButton == LEFTBUTTON
|
914
921
|
x = (event.last_x / @zoom).to_i
|
@@ -925,9 +932,13 @@ class FXMap < Map
|
|
925
932
|
def mmb_release_cb(server, sel, event)
|
926
933
|
if @mouseButton
|
927
934
|
@canvas.ungrab
|
928
|
-
@mouseButton = nil
|
929
935
|
@canvas.dragCursor = @@cursor_arrow
|
930
|
-
|
936
|
+
if @mouseButton == LEFTBUTTON
|
937
|
+
draw
|
938
|
+
else
|
939
|
+
@canvas.repaint
|
940
|
+
end
|
941
|
+
@mouseButton = nil
|
931
942
|
end
|
932
943
|
end
|
933
944
|
|
@@ -1262,8 +1273,10 @@ class FXMap < Map
|
|
1262
1273
|
LAYOUT_TOP|LAYOUT_LEFT,
|
1263
1274
|
0, 0, width, height)
|
1264
1275
|
@dirty = true
|
1265
|
-
@canvas.connect(SEL_UPDATE, method(:update_cb))
|
1266
|
-
|
1276
|
+
# @canvas.connect(SEL_UPDATE, method(:update_cb))
|
1277
|
+
if fxversion =~ /^1.4/
|
1278
|
+
@canvas.connect(SEL_QUERY_TIP, method(:tooltip_cb))
|
1279
|
+
end
|
1267
1280
|
|
1268
1281
|
@canvas.connect(SEL_PAINT, method(:draw))
|
1269
1282
|
@canvas.backColor = @options['BG Color']
|
@@ -1344,9 +1357,6 @@ class FXMap < Map
|
|
1344
1357
|
# Recreate pathmap. We need to recreate pathmap for all paths
|
1345
1358
|
# as the removal of one path may help shorten the path of another.
|
1346
1359
|
create_pathmap
|
1347
|
-
|
1348
|
-
@automap.remove(rooms) if @automap
|
1349
|
-
|
1350
1360
|
draw()
|
1351
1361
|
end
|
1352
1362
|
|
@@ -1628,6 +1638,11 @@ class FXMap < Map
|
|
1628
1638
|
ws_2 = WS_2 * @zoom
|
1629
1639
|
hs_2 = HS_2 * @zoom
|
1630
1640
|
|
1641
|
+
#---- dummy check to catch an ugly bug that I cannot track...
|
1642
|
+
if @pmap.size != @width or @pmap[0].size != @height
|
1643
|
+
puts "**********ERROR: pmap sizes not != #{@width}x#{@height}"
|
1644
|
+
end
|
1645
|
+
|
1631
1646
|
# First, draw horizontal lines
|
1632
1647
|
(0...@height).each { |yy|
|
1633
1648
|
(0..@width-2).each { |xx|
|
@@ -40,7 +40,7 @@ require 'IFMapper/FXMapColorBox'
|
|
40
40
|
class FXMapperWindow < FXMainWindow
|
41
41
|
|
42
42
|
PROGRAM_NAME = "Interactive Fiction Mapper"
|
43
|
-
VERSION = 0.8
|
43
|
+
VERSION = '0.8.5'
|
44
44
|
AUTHOR = "Gonzalo Garramuno"
|
45
45
|
TITLE = "#{PROGRAM_NAME} v#{VERSION} - Written by #{AUTHOR}"
|
46
46
|
|
@@ -371,21 +371,42 @@ class FXMapperWindow < FXMainWindow
|
|
371
371
|
|
372
372
|
# Add rooms
|
373
373
|
r_to_nr = {} # orig room to new room hash
|
374
|
-
sel[0]
|
374
|
+
rooms = sel[0]
|
375
|
+
rooms.each { |r|
|
375
376
|
nr = map.new_room(r.x + pos[0], r.y + pos[1])
|
377
|
+
nr.selected = true
|
376
378
|
nr.copy(r) # copy the room data
|
377
379
|
r_to_nr[r] = nr
|
378
380
|
}
|
379
381
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
382
|
+
if rooms.empty?
|
383
|
+
# Add connections only (no rooms copied)
|
384
|
+
sel[1].each { |c|
|
385
|
+
exitA = c.roomA.exits.index(c)
|
386
|
+
exitB = c.roomB.exits.rindex(c)
|
387
|
+
roomA = c.roomA
|
388
|
+
roomB = c.roomB
|
389
|
+
sect = map.sections[map.section]
|
390
|
+
next unless sect.rooms.include?(roomA) and sect.rooms.include?(roomB)
|
391
|
+
begin
|
392
|
+
c = map.new_connection(roomA, exitA, roomB, exitB)
|
393
|
+
c.selected = true
|
394
|
+
rescue
|
395
|
+
end
|
396
|
+
}
|
397
|
+
else
|
398
|
+
# Add connections
|
399
|
+
sel[1].each { |c|
|
400
|
+
exitA = c.roomA.exits.index(c)
|
401
|
+
exitB = c.roomB.exits.rindex(c)
|
402
|
+
roomA = r_to_nr[c.roomA]
|
403
|
+
roomB = r_to_nr[c.roomB]
|
404
|
+
c = map.new_connection(roomA, exitA, roomB, exitB)
|
405
|
+
c.selected = true
|
406
|
+
}
|
407
|
+
end
|
408
|
+
|
409
|
+
map.create_pathmap
|
389
410
|
map.draw
|
390
411
|
end
|
391
412
|
end
|
data/lib/IFMapper/FXRoom.rb
CHANGED
@@ -6,11 +6,22 @@ require 'IFMapper/FXRoomDialogBox'
|
|
6
6
|
# Class used to reprent an IF room
|
7
7
|
#
|
8
8
|
class FXRoom < Room
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :xx, :yy
|
10
10
|
attr_accessor :selected
|
11
11
|
|
12
12
|
@@win = nil
|
13
13
|
|
14
|
+
def marshal_dump
|
15
|
+
super + [ @selected ]
|
16
|
+
end
|
17
|
+
|
18
|
+
def marshal_load(vars)
|
19
|
+
super(vars)
|
20
|
+
@selected = vars[-1]
|
21
|
+
@xx = x * WW + WS_2
|
22
|
+
@yy = y * HH + HS_2
|
23
|
+
end
|
24
|
+
|
14
25
|
def initialize(x, y, *opts)
|
15
26
|
@xx = x * WW + WS_2
|
16
27
|
@yy = y * HH + HS_2
|
@@ -202,6 +213,7 @@ class FXRoom < Room
|
|
202
213
|
# Draw text line wrapping after certain length (in chars)
|
203
214
|
#
|
204
215
|
def draw_text_wrap(dc, x, y, zoom, maxLen, text)
|
216
|
+
return if y > (@yy + H) * zoom
|
205
217
|
if text.size > maxLen
|
206
218
|
str = text
|
207
219
|
fh = dc.font.getFontHeight
|
data/lib/IFMapper/FXSpline.rb
CHANGED
data/lib/IFMapper/IFMReader.rb
CHANGED
@@ -53,12 +53,12 @@ class IFMReader
|
|
53
53
|
# We start map at 1, 1
|
54
54
|
@x, @y = [0, 0]
|
55
55
|
@room = @item = @task = nil
|
56
|
-
@map.section = 0
|
57
56
|
|
58
57
|
if @map.kind_of?(FXMap)
|
59
58
|
@map.options['Edit on Creation'] = false
|
60
59
|
@map.window.hide
|
61
60
|
end
|
61
|
+
@map.section = 0
|
62
62
|
|
63
63
|
@last_section = 0
|
64
64
|
@ignore_first_section = true
|
@@ -545,7 +545,6 @@ class IFMReader
|
|
545
545
|
# a) Adjust map's width/height
|
546
546
|
# b) Shift all rooms so that no rooms are in negative locations
|
547
547
|
#
|
548
|
-
|
549
548
|
def initialize(file, map = Map.new('IFM Imported Map'))
|
550
549
|
@tags = {}
|
551
550
|
@map = map
|
@@ -84,6 +84,21 @@ class FXConnection
|
|
84
84
|
x1, y1 = [p[0][0], p[0][1]]
|
85
85
|
x2, y2 = [p[-1][0], p[-1][1]]
|
86
86
|
pdf_draw_arrow(pdf, opts, x1, y1, x2, y2)
|
87
|
+
|
88
|
+
if @type == LOCKED_DOOR
|
89
|
+
t = p.size / 2
|
90
|
+
x1, y1 = [ p[t].x, p[t].y ]
|
91
|
+
x2, y2 = [ p[t-2].x, p[t-2].y ]
|
92
|
+
|
93
|
+
v = [ (x2-x1), (y2-y1) ]
|
94
|
+
t = 10 / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
95
|
+
v = [ v[0]*t, v[1]*t ]
|
96
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
97
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
98
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
99
|
+
pdf.move_to(x1, y1)
|
100
|
+
pdf.line_to(x2, y2).stroke
|
101
|
+
end
|
87
102
|
end
|
88
103
|
|
89
104
|
def pdf_draw_simple(pdf, opts)
|
data/lib/IFMapper/Room.rb
CHANGED
@@ -3,12 +3,13 @@
|
|
3
3
|
# Class used to represent a Room or Location in a Map.
|
4
4
|
#
|
5
5
|
class Room
|
6
|
-
attr_accessor :name
|
7
|
-
attr_accessor :objects
|
8
|
-
attr_accessor :tasks
|
9
|
-
attr_reader :exits
|
10
|
-
attr_accessor :darkness
|
11
|
-
attr_accessor :x, :y
|
6
|
+
attr_accessor :name # Name of room
|
7
|
+
attr_accessor :objects # Objects found in room
|
8
|
+
attr_accessor :tasks # Tasks that need to be performed in room
|
9
|
+
attr_reader :exits # An array of 8 possible exits in room
|
10
|
+
attr_accessor :darkness # Is room in darkness?
|
11
|
+
attr_accessor :x, :y # Room location in grid
|
12
|
+
attr_accessor :desc # Room description
|
12
13
|
|
13
14
|
DIRECTIONS = [
|
14
15
|
'n',
|
@@ -32,6 +33,21 @@ class Room
|
|
32
33
|
7 => [ -1, -1 ]
|
33
34
|
}
|
34
35
|
|
36
|
+
def marshal_load(vars)
|
37
|
+
@name = vars.shift
|
38
|
+
@objects = vars.shift
|
39
|
+
@tasks = vars.shift
|
40
|
+
@exits = vars.shift
|
41
|
+
@darkness = vars.shift
|
42
|
+
@x = vars.shift
|
43
|
+
@y = vars.shift
|
44
|
+
@desc = vars.shift if not vars.empty? and vars[0].kind_of?(String)
|
45
|
+
end
|
46
|
+
|
47
|
+
def marshal_dump
|
48
|
+
[ @name, @objects, @tasks, @exits, @darkness, @x, @y, @desc ]
|
49
|
+
end
|
50
|
+
|
35
51
|
def [](dir)
|
36
52
|
return @exits[dir]
|
37
53
|
end
|
@@ -101,6 +117,7 @@ class Room
|
|
101
117
|
@objects = b.objects
|
102
118
|
@tasks = b.tasks
|
103
119
|
@darkness = b.darkness
|
120
|
+
@desc = b.desc
|
104
121
|
end
|
105
122
|
|
106
123
|
|
@@ -7,15 +7,16 @@
|
|
7
7
|
#
|
8
8
|
# This code is based on Perl code by Dave Chapeskie, used in IFM,
|
9
9
|
# albeit it has been enhanced to handle multi-line commands, room stub
|
10
|
-
# exits, objects parsing and the ability to parse
|
11
|
-
# they are being spit out.
|
10
|
+
# exits and oneway exits, objects parsing and the ability to parse
|
11
|
+
# transcripts as they are being spit out.
|
12
12
|
#
|
13
13
|
class TranscriptReader
|
14
14
|
|
15
15
|
PROMPT = /^>\s*/
|
16
16
|
LOOK = /^l(ook)?/i
|
17
17
|
UNDO = /^undo$/i
|
18
|
-
|
18
|
+
RESTART = /^restart$/i
|
19
|
+
RESTORE = /^restore$/i
|
19
20
|
IGNORE = /transcript/i
|
20
21
|
OTHERS = /^(read|inventory$|i$)/i
|
21
22
|
UNSCRIPT = /^unscript$/i
|
@@ -23,8 +24,9 @@ class TranscriptReader
|
|
23
24
|
TAKE = /^(take|get)\s+(a\s+|the\s+)?(.*)/i
|
24
25
|
DROP = /^(drop|leave)\s+()/i
|
25
26
|
STARTUP = /(^[A-Z]+$|Copyright|\([cC]\)\s*\d|Trademark|Release|Version|[Ss]erial [Nn]umber|Written by)/
|
26
|
-
DARKNESS =
|
27
|
+
DARKNESS = /^dark(ness)?$|It is pitch black/i
|
27
28
|
DEAD = /(You die|You have died|You are dead)/i
|
29
|
+
YES = /^y(es)/i
|
28
30
|
|
29
31
|
# Compass direction command -> direction mapping.
|
30
32
|
DIRMAP = {
|
@@ -54,8 +56,7 @@ class TranscriptReader
|
|
54
56
|
|
55
57
|
|
56
58
|
## Change this to non-dil to print out debugging info
|
57
|
-
@@debug =
|
58
|
-
|
59
|
+
@@debug = nil
|
59
60
|
|
60
61
|
def debug(*msg)
|
61
62
|
if @@debug
|
@@ -66,6 +67,7 @@ class TranscriptReader
|
|
66
67
|
## Possible nessages indicating get/take succeeded
|
67
68
|
TAKE_OK = [
|
68
69
|
/taken/i,
|
70
|
+
/you\s+pick\s+up\s+the\s+?/i,
|
69
71
|
/you\s+now\s+have\s+(got\s+)?/i,
|
70
72
|
]
|
71
73
|
|
@@ -76,6 +78,8 @@ class TranscriptReader
|
|
76
78
|
#
|
77
79
|
def take(move, objs)
|
78
80
|
return unless @here
|
81
|
+
endl = ''
|
82
|
+
endl = "\n" if @here.objects != '' and @here.objects[-1,1] != "\n"
|
79
83
|
objs.each { |cmd, dummy, obj|
|
80
84
|
next if not obj
|
81
85
|
|
@@ -88,8 +92,9 @@ class TranscriptReader
|
|
88
92
|
next if not o
|
89
93
|
status = move[:reply].to_s
|
90
94
|
TAKE_OK.each { |re|
|
91
|
-
if status =~ re and not @objects.has_key?(o)
|
92
|
-
|
95
|
+
if status =~ re and not @objects.has_key?(o) and
|
96
|
+
not @here.objects =~ /#{o}/
|
97
|
+
@here.objects << endl << o << "\n"
|
93
98
|
@objects[o] = 1
|
94
99
|
@last_obj = o
|
95
100
|
break
|
@@ -101,8 +106,9 @@ class TranscriptReader
|
|
101
106
|
o, status = reply.split(':')
|
102
107
|
next if not status
|
103
108
|
o = @last_obj if o =~ IT
|
104
|
-
if o and not @objects.has_key?(o)
|
105
|
-
|
109
|
+
if o and not @objects.has_key?(o) and
|
110
|
+
not @here.objects =~ /#{o}/
|
111
|
+
@here.objects << endl << o << "\n"
|
106
112
|
@objects[o] = 1
|
107
113
|
@last_obj = o
|
108
114
|
end
|
@@ -115,7 +121,7 @@ class TranscriptReader
|
|
115
121
|
# Add a new room to the automapper
|
116
122
|
#
|
117
123
|
def add(room)
|
118
|
-
@rooms
|
124
|
+
@rooms << room
|
119
125
|
end
|
120
126
|
|
121
127
|
#
|
@@ -149,12 +155,12 @@ class TranscriptReader
|
|
149
155
|
|
150
156
|
EXITS_REGEX =
|
151
157
|
[
|
152
|
-
# You can go south or east
|
153
|
-
|
158
|
+
# (You can) go south or east
|
159
|
+
/\s+go\s+#{DIR}\s+#{OR}\s+#{DIR}\b/i,
|
154
160
|
# You can go south
|
155
161
|
/you\s+can\s+go\s+#{DIR}\b/i,
|
156
162
|
# to the east or west
|
157
|
-
/to\s+the\s+#{DIR}\s+#{OR}\s
|
163
|
+
/to\s+the\s+#{DIR}\s+#{OR}\s+(to\s+the\s+)?#{DIR}\b/i,
|
158
164
|
# to the east
|
159
165
|
/to\s+the\s+#{DIR}\b/i,
|
160
166
|
# paths lead west and north
|
@@ -170,6 +176,10 @@ class TranscriptReader
|
|
170
176
|
/(running|leading|heading|opening|branching|lying|wandering|looking|bending)\s+#{DIR}\b/i,
|
171
177
|
]
|
172
178
|
|
179
|
+
# passage westwards
|
180
|
+
# gap in the northeast corner
|
181
|
+
|
182
|
+
|
173
183
|
EXITS_SPECIAL = {
|
174
184
|
/four\s+directions/i => [0, 2, 4, 6],
|
175
185
|
/four\s+compass\s+points/i => [0, 2, 4, 6],
|
@@ -256,16 +266,37 @@ class TranscriptReader
|
|
256
266
|
|
257
267
|
|
258
268
|
# Step 2
|
269
|
+
@restart = false
|
259
270
|
tele = nil
|
260
271
|
@moves.each { |move|
|
261
272
|
cmd = move[:cmd]
|
262
273
|
next if cmd =~ IGNORE or cmd =~ OTHERS
|
263
274
|
if cmd =~ UNSCRIPT
|
264
275
|
tele = 1
|
276
|
+
@here = nil
|
265
277
|
next
|
266
278
|
end
|
267
279
|
|
268
|
-
|
280
|
+
if @restart and cmd =~ YES
|
281
|
+
@here = nil
|
282
|
+
else
|
283
|
+
@restart = false
|
284
|
+
tele = nil
|
285
|
+
end
|
286
|
+
|
287
|
+
if cmd =~ RESTART
|
288
|
+
@restart = true
|
289
|
+
tele = 1
|
290
|
+
end
|
291
|
+
|
292
|
+
if cmd =~ RESTORE
|
293
|
+
if move[:reply] =~ /Ok/
|
294
|
+
@here = nil
|
295
|
+
tele = 1
|
296
|
+
else
|
297
|
+
next
|
298
|
+
end
|
299
|
+
end
|
269
300
|
|
270
301
|
name = nil
|
271
302
|
desc = ''
|
@@ -287,12 +318,14 @@ class TranscriptReader
|
|
287
318
|
name = nil
|
288
319
|
roomflag = false
|
289
320
|
desc_gap = false
|
321
|
+
@here = nil
|
322
|
+
tele = 1
|
290
323
|
next
|
291
324
|
end
|
292
325
|
next if startup and r !~ BLANK
|
293
326
|
startup = false
|
294
327
|
|
295
|
-
if not roomflag and r !~ BLANK and
|
328
|
+
if not roomflag and r !~ BLANK and room_name(r)
|
296
329
|
debug "set roomflag with #{r}"
|
297
330
|
roomflag = true
|
298
331
|
name = r
|
@@ -316,6 +349,7 @@ class TranscriptReader
|
|
316
349
|
end
|
317
350
|
desc = nil if desc == ''
|
318
351
|
|
352
|
+
puts "name: #{name} tele:#{tele}"
|
319
353
|
rooms << {
|
320
354
|
:name => name,
|
321
355
|
:desc => desc,
|
@@ -361,35 +395,84 @@ class TranscriptReader
|
|
361
395
|
debug "\t TO: #{@here}"
|
362
396
|
end
|
363
397
|
|
398
|
+
# Make sure the user has not deleted the current room from map
|
399
|
+
# and that we are in the proper section.
|
400
|
+
if @here
|
401
|
+
found = false
|
402
|
+
@map.sections.each_with_index { |sect, idx|
|
403
|
+
if sect.rooms.include?(@here)
|
404
|
+
found = true
|
405
|
+
if idx != @map.section
|
406
|
+
@map.fit
|
407
|
+
@map.section = idx
|
408
|
+
end
|
409
|
+
break
|
410
|
+
end
|
411
|
+
}
|
412
|
+
@here = nil if not found
|
413
|
+
end
|
414
|
+
|
364
415
|
# If it is a look command or we don't know where we are yet,
|
365
416
|
# set current room.
|
366
417
|
if move[:look] or not @here
|
418
|
+
@here = find_room(name, desc)
|
367
419
|
@here = new_room(move, name, desc) unless @here
|
368
420
|
@here.selected = true
|
369
421
|
next
|
370
422
|
end
|
371
423
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
424
|
+
cmd.sub!(GO, '')
|
425
|
+
dir = $3
|
426
|
+
debug "MOVED IN DIRECTION: #{dir} CMD LEFT:#{cmd}"
|
376
427
|
if not cmd
|
377
428
|
debug "Oops... run out of commands."
|
378
429
|
break
|
379
430
|
end
|
380
|
-
|
381
|
-
|
382
|
-
|
431
|
+
|
432
|
+
# Otherwise, assume we moved in some way. Try to find the new room.
|
433
|
+
if name =~ DARKNESS
|
434
|
+
idx = DIRMAP[dir] || ODIRMAP[dir]
|
435
|
+
# Moving to a dark room is special. We verify the exit to see
|
436
|
+
# if it was already moving to a dark room (in which case it
|
437
|
+
# becomes there) or if it was moving to some other room (in
|
438
|
+
# which case we flag it as dark and make it there)
|
439
|
+
if idx and @here[idx]
|
440
|
+
c = @here[idx]
|
441
|
+
|
442
|
+
if c.roomA == @here
|
443
|
+
b = c.roomB
|
444
|
+
else
|
445
|
+
b = c.roomA
|
446
|
+
end
|
447
|
+
|
448
|
+
if not b
|
449
|
+
there = nil
|
450
|
+
else
|
451
|
+
if b.name !~ DARKNESS
|
452
|
+
b.darkness = true
|
453
|
+
end
|
454
|
+
there = b
|
455
|
+
end
|
456
|
+
else
|
457
|
+
# No connection yet, create dark room
|
458
|
+
there = nil
|
459
|
+
end
|
460
|
+
else
|
461
|
+
there = find_room(name, desc)
|
462
|
+
end
|
463
|
+
|
464
|
+
next if there == @here
|
465
|
+
|
466
|
+
|
467
|
+
go = nil
|
383
468
|
if DIRMAP[dir]
|
384
469
|
dir = DIRMAP[dir]
|
385
|
-
go = nil
|
386
470
|
elsif ODIRMAP[dir]
|
387
471
|
go = ODIRMAP[dir]
|
388
472
|
dir = choose_dir(@here, there, go)
|
389
473
|
else
|
390
|
-
# special move ---
|
474
|
+
# special move --- teleport/death/etc.
|
391
475
|
dir = choose_dir(@here, there)
|
392
|
-
go = nil
|
393
476
|
end
|
394
477
|
debug "MOVED IN DIR INDEX: #{dir}"
|
395
478
|
|
@@ -408,6 +491,7 @@ class TranscriptReader
|
|
408
491
|
@moves.clear
|
409
492
|
@map.fit
|
410
493
|
if @map.kind_of?(FXMap)
|
494
|
+
@map.clear_selection
|
411
495
|
@here.selected = true if @here
|
412
496
|
@map.zoom = @map.zoom
|
413
497
|
@map.center_view_on_room(@here) if @here
|
@@ -419,56 +503,64 @@ class TranscriptReader
|
|
419
503
|
def find_room(name, desc)
|
420
504
|
bestscore = 0
|
421
505
|
best = nil
|
422
|
-
@rooms.each { |r, room|
|
423
|
-
score = 0
|
424
|
-
|
425
|
-
|
426
|
-
if desc and room[:desc]
|
427
|
-
# We have a description...
|
428
|
-
# Try exact description match first
|
429
|
-
score += 10 if room[:desc] == desc
|
430
|
-
|
431
|
-
# Try substring match
|
432
|
-
score += 5 if room[:desc].index(desc)
|
433
|
-
|
434
|
-
# If still no luck, try first N words
|
435
|
-
if score == 0
|
436
|
-
dwords = room[:desc].split(' ')
|
437
|
-
words = desc.split(' ')
|
438
|
-
match = true
|
439
|
-
0.upto(DESC_MINWORDS) { |i|
|
440
|
-
if words[i] != dwords[i]
|
441
|
-
match = false
|
442
|
-
break
|
443
|
-
end
|
444
|
-
}
|
445
506
|
|
446
|
-
|
507
|
+
@map.sections.each_with_index { |sect, idx|
|
508
|
+
sect.rooms.each { |room|
|
509
|
+
score = 0
|
510
|
+
|
511
|
+
if desc and room.desc
|
512
|
+
# We have a description...
|
513
|
+
# Try exact description match first
|
514
|
+
score += 10 if room.desc == desc
|
515
|
+
|
516
|
+
# Try substring match
|
517
|
+
score += 5 if room.desc.index(desc)
|
518
|
+
|
519
|
+
# If still no luck, try first N words
|
520
|
+
if score == 0
|
521
|
+
dwords = room.desc.split(' ')
|
522
|
+
words = desc.split(' ')
|
523
|
+
match = true
|
524
|
+
0.upto(DESC_MINWORDS) { |i|
|
525
|
+
if words[i] != dwords[i]
|
526
|
+
match = false
|
527
|
+
break
|
528
|
+
end
|
529
|
+
}
|
530
|
+
|
531
|
+
score += 2 if match and room.name == name
|
532
|
+
end
|
533
|
+
else
|
534
|
+
# Just the name, not so good
|
535
|
+
score += 1 if room.name == name
|
447
536
|
end
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
next if score <= bestscore
|
453
|
-
bestscore = score
|
454
|
-
best = [r, room[:section]]
|
537
|
+
next if score <= bestscore
|
538
|
+
bestscore = score
|
539
|
+
best = [room, idx]
|
540
|
+
}
|
455
541
|
}
|
542
|
+
|
456
543
|
return nil if not best
|
457
|
-
|
544
|
+
|
545
|
+
# Make sure we are in the right section
|
458
546
|
if best[1] != @map.section
|
459
|
-
|
547
|
+
@map.fit
|
460
548
|
@map.section = best[1]
|
461
549
|
end
|
550
|
+
best[0].desc = desc if not best[0].desc and desc
|
462
551
|
return best[0]
|
463
552
|
end
|
464
|
-
|
553
|
+
|
465
554
|
#
|
466
555
|
# Determine if line corresponds to a room name
|
467
556
|
#
|
468
|
-
def
|
469
|
-
# Remove unwanted stuff
|
557
|
+
def room_name(line)
|
558
|
+
# Remove unwanted stuff line (on the bed)
|
470
559
|
line.sub!(NAME_REMOVE, '')
|
471
560
|
|
561
|
+
# Check if user/game has created a room with that name already
|
562
|
+
return true if find_room(line, nil)
|
563
|
+
|
472
564
|
# Remove periods from salutations
|
473
565
|
line.sub!(SALUTATIONS, '\1')
|
474
566
|
|
@@ -482,11 +574,24 @@ class TranscriptReader
|
|
482
574
|
return false if words.size > NAME_MAXWORDS
|
483
575
|
|
484
576
|
# Check if we start line with uncapitalized words or symbols
|
485
|
-
return false if line =~ /^[ a-z\/\\\-\(\)]/
|
577
|
+
return false if line =~ /^[ a-z\/\\\-\(\)'#]/
|
486
578
|
|
579
|
+
|
580
|
+
# If not, check all words of 4 chars or more are capitalized
|
581
|
+
# and that there are no 3 or more short letter words together
|
582
|
+
# (which means a diagram)
|
583
|
+
num = 0
|
487
584
|
words.each { |w|
|
488
|
-
return false if w =~ /^[a-z]/ and w.size > NAME_MAXUNCAP
|
585
|
+
return false if w =~ /^[a-z]/ and w.size > NAME_MAXUNCAP
|
586
|
+
if w.size <= 2
|
587
|
+
num += 1
|
588
|
+
return false if num > 2
|
589
|
+
else
|
590
|
+
num = 0
|
591
|
+
end
|
489
592
|
}
|
593
|
+
|
594
|
+
# Okay, it is a room.
|
490
595
|
return true
|
491
596
|
end
|
492
597
|
|
@@ -501,6 +606,25 @@ class TranscriptReader
|
|
501
606
|
r = @map.new_room(0, 0)
|
502
607
|
r.name = name
|
503
608
|
else
|
609
|
+
|
610
|
+
if name =~ DARKNESS
|
611
|
+
dark = true
|
612
|
+
else
|
613
|
+
dark = false
|
614
|
+
if from[dir]
|
615
|
+
# oops, we had a connection there.
|
616
|
+
c = from[dir]
|
617
|
+
b = c.roomB
|
618
|
+
if b and b.name =~ DARKNESS
|
619
|
+
# Was it a dark room that is now lit?
|
620
|
+
# if so, set dark flag and delete dark room
|
621
|
+
@map.delete_room(b)
|
622
|
+
dark = true
|
623
|
+
c = nil
|
624
|
+
end
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
504
628
|
x = from.x
|
505
629
|
y = from.y
|
506
630
|
dx, dy = Room::DIR_TO_VECTOR[dir]
|
@@ -515,28 +639,23 @@ class TranscriptReader
|
|
515
639
|
debug "+++ New Room #{name} from #{from}"
|
516
640
|
r = @map.new_room(x, y)
|
517
641
|
r.name = name
|
642
|
+
r.darkness = dark
|
518
643
|
c = nil
|
519
644
|
if from[dir]
|
520
645
|
# oops, we had a connection there.
|
521
646
|
c = from[dir]
|
522
647
|
b = c.roomB
|
523
|
-
if
|
648
|
+
if c.stub?
|
524
649
|
# Stub connection. Update it.
|
525
650
|
debug "\tUPDATE #{c}"
|
526
651
|
odir = (dir + 4) % 8
|
652
|
+
c.exitAtext = go if go
|
527
653
|
c.roomB = r
|
528
654
|
r[odir] = c
|
529
655
|
debug "\tNOW IT IS #{c}"
|
530
|
-
elsif b.name =~ DARKNESS
|
531
|
-
# Was it a dark room that is now lit?
|
532
|
-
@map.delete_connection(c)
|
533
|
-
@map.delete_room(b)
|
534
|
-
r.darkness = true
|
535
|
-
c = nil
|
536
656
|
else
|
537
657
|
# Probably a link that is complex
|
538
658
|
# or oneway. Shift it to some other location
|
539
|
-
exitB = b.exits.rindex(c)
|
540
659
|
shift_link(from, dir)
|
541
660
|
c = nil
|
542
661
|
end
|
@@ -551,7 +670,7 @@ class TranscriptReader
|
|
551
670
|
parse_exits(r, desc)
|
552
671
|
|
553
672
|
# Update room description
|
554
|
-
|
673
|
+
r.desc = desc
|
555
674
|
return r
|
556
675
|
end
|
557
676
|
|
@@ -594,7 +713,8 @@ class TranscriptReader
|
|
594
713
|
debug "\tMOVE #{c} DIR: #{dir}"
|
595
714
|
if c.stub?
|
596
715
|
# Stub connection, fill it
|
597
|
-
c.roomB
|
716
|
+
c.roomB = to
|
717
|
+
c.exitAtext = go if go
|
598
718
|
# we still need to check the destination to[odir]...
|
599
719
|
if not to[odir]
|
600
720
|
# nothing to do
|
@@ -604,7 +724,11 @@ class TranscriptReader
|
|
604
724
|
else
|
605
725
|
# this end cannot be deleted. we need to shift odir
|
606
726
|
debug "\tCHOOSE NEW DIR for #{odir}"
|
607
|
-
|
727
|
+
rgo = nil
|
728
|
+
if go
|
729
|
+
rgo = rgo % 2 == 0? go - 1 : go + 1
|
730
|
+
end
|
731
|
+
odir = choose_dir(to, from, rgo, dir)
|
608
732
|
@map.delete_connection(to[odir]) if to[odir]
|
609
733
|
debug "\tSHIFTED DESTINATION TO EXIT #{odir}"
|
610
734
|
end
|
@@ -658,7 +782,11 @@ class TranscriptReader
|
|
658
782
|
c.exitBtext = go if go
|
659
783
|
else
|
660
784
|
# We need to change odir to something else
|
661
|
-
|
785
|
+
rgo = nil
|
786
|
+
if go
|
787
|
+
rgo = go % 2 == 0? go - 1 : go + 1
|
788
|
+
end
|
789
|
+
odir = choose_dir(to, from, rgo, dir)
|
662
790
|
@map.delete_connection(to[odir]) if to[odir] and to[odir].stub?
|
663
791
|
c = nil
|
664
792
|
end
|
@@ -677,8 +805,9 @@ class TranscriptReader
|
|
677
805
|
if c
|
678
806
|
# If so, make that connection go both ways and attach it to
|
679
807
|
# current direction.
|
680
|
-
from[dir]
|
681
|
-
c.dir
|
808
|
+
from[dir] = c
|
809
|
+
c.dir = Connection::BOTH
|
810
|
+
c.exitAtext = go if go
|
682
811
|
end
|
683
812
|
end
|
684
813
|
|
@@ -707,10 +836,12 @@ class TranscriptReader
|
|
707
836
|
next if not e
|
708
837
|
roomA = e.roomA
|
709
838
|
roomB = e.roomB
|
710
|
-
if roomA == a and roomB == b and
|
839
|
+
if roomA == a and roomB == b and
|
840
|
+
(e.exitBtext == rgo or e.exitAtext == go)
|
711
841
|
e.exitAtext = go
|
712
842
|
return idx
|
713
|
-
elsif roomB == a and roomA == b and e.exitAtext == rgo
|
843
|
+
elsif roomB == a and roomA == b and (e.exitAtext == rgo or
|
844
|
+
e.exitBtext == go)
|
714
845
|
e.exitBtext = go
|
715
846
|
return idx
|
716
847
|
end
|
@@ -769,7 +900,7 @@ class TranscriptReader
|
|
769
900
|
end
|
770
901
|
|
771
902
|
def stop
|
772
|
-
@t.
|
903
|
+
@t.kill if @t
|
773
904
|
end
|
774
905
|
|
775
906
|
def destroy
|
@@ -783,7 +914,6 @@ class TranscriptReader
|
|
783
914
|
@map = map
|
784
915
|
@objects = {}
|
785
916
|
@moves = []
|
786
|
-
@rooms = {}
|
787
917
|
@here = nil
|
788
918
|
@section = -1
|
789
919
|
@last_obj = nil
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
|
|
3
3
|
specification_version: 1
|
4
4
|
name: ifmapper
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.8.
|
7
|
-
date: 2005-08-
|
6
|
+
version: 0.8.5
|
7
|
+
date: 2005-08-24
|
8
8
|
summary: Interactive Fiction Mapping Tool.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -28,29 +28,29 @@ authors:
|
|
28
28
|
- Gonzalo Garramuno
|
29
29
|
files:
|
30
30
|
- IFMapper.rbw
|
31
|
-
- lib/IFMapper/FXMap.rb
|
32
31
|
- lib/IFMapper/Map.rb
|
33
|
-
- lib/IFMapper/FXSpline.rb
|
34
32
|
- lib/IFMapper/FXSection.rb
|
35
|
-
- lib/IFMapper/FXRoom.rb
|
36
|
-
- lib/IFMapper/FXMapDialogBox.rb
|
37
33
|
- lib/IFMapper/FXSectionDialogBox.rb
|
38
|
-
- lib/IFMapper/FXMapperWindow.rb
|
39
34
|
- lib/IFMapper/Room.rb
|
40
35
|
- lib/IFMapper/Section.rb
|
41
36
|
- lib/IFMapper/FXConnection.rb
|
42
37
|
- lib/IFMapper/FXMapColorBox.rb
|
38
|
+
- lib/IFMapper/IFMReader.rb
|
43
39
|
- lib/IFMapper/IFMWriter.rb
|
44
40
|
- lib/IFMapper/FXWarningBox.rb
|
45
|
-
- lib/IFMapper/PDFMapExporter.rb
|
46
41
|
- lib/IFMapper/FXMapperSettings.rb
|
42
|
+
- lib/IFMapper/FXMap.rb
|
43
|
+
- lib/IFMapper/FXRoom.rb
|
47
44
|
- lib/IFMapper/AStar.rb
|
45
|
+
- lib/IFMapper/FXMapperWindow.rb
|
48
46
|
- lib/IFMapper/Connection.rb
|
49
47
|
- lib/IFMapper/MapPrinting.rb
|
50
48
|
- lib/IFMapper/FXDCPostscript.rb
|
51
49
|
- lib/IFMapper/FXDCPrint.rb
|
52
|
-
- lib/IFMapper/
|
50
|
+
- lib/IFMapper/PDFMapExporter.rb
|
53
51
|
- lib/IFMapper/TranscriptReader.rb
|
52
|
+
- lib/IFMapper/FXMapDialogBox.rb
|
53
|
+
- lib/IFMapper/FXSpline.rb
|
54
54
|
- lib/IFMapper/FXAboutDialogBox.rb
|
55
55
|
- lib/IFMapper/FXSearchDialogBox.rb
|
56
56
|
- lib/IFMapper/FXMapFileDialog.rb
|