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