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 CHANGED
@@ -1,9 +1,64 @@
1
1
 
2
- v0.8.1 - Just some fixes to the automapper, as it was failing on some relatively
3
- simple games.
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 Bedroom".
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.1'
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/'
@@ -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, @type, @dir, @roomA, @roomB, @exitAtext, @exitBtext ]
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]]
@@ -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 update_cb(sender, sel, event)
790
- # if sel == FXWindow::ID_QUERY_TIP
791
- # p "tooltip"
792
- # end
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
- draw
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
- # FXMAPFUNC(SEL_UPDATE, FXWindow::ID_QUERY_TIP, 'tooltip_cb')
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|
@@ -29,7 +29,7 @@ class FXMapDialogBox < FXDialogBox
29
29
  rooms = []
30
30
  @map.sections.each { |s|
31
31
  s.rooms.each { |r|
32
- if r.x <= w or r.y <= h
32
+ if r.x >= w or r.y >= h
33
33
  rooms << [s, r]
34
34
  end
35
35
  }
@@ -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].each { |r|
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
- # Add connections
381
- sel[1].each { |c|
382
- exitA = c.roomA.exits.index(c)
383
- exitB = c.roomB.exits.rindex(c)
384
- roomA = r_to_nr[c.roomA]
385
- roomB = r_to_nr[c.roomB]
386
- c = map.new_connection(roomA, exitA, roomB, exitB)
387
- map.path_find(c)
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
@@ -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 :x, :y, :xx, :yy
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
@@ -32,7 +32,7 @@ class FXSpline
32
32
  x2 = x2 * x2
33
33
  y2 = p[x+2][1] - p[x+1][1]
34
34
  y2 = y2 * y2
35
- num = Math.sqrt( x2 + y2 ).to_i / 8
35
+ num = Math.sqrt( x2 + y2 ).to_i / 16
36
36
  bspline_solve(pts, p[x..x+3], num)
37
37
  }
38
38
  return pts
@@ -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 transcripts as
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
- TELEPORT = /^(restart|restore)$/i
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 = /dark|It is pitch black/i
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 = 1
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
- @here.objects << o << "\n"
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
- @here.objects << o << "\n"
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[room] = {:section => @map.section, :desc => nil }
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
- /you\s+can\s+go\s+#{DIR}\s+#{OR}\s+#{DIR}\b/i,
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+#{DIR}\b/i,
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
- tele = 1 if cmd =~ TELEPORT
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 roomname(r)
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
- # Otherwise, assume we moved in some way. Try to find the new room.
373
- there = find_room(name, desc)
374
- next if there == @here
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
- cmd.sub!(GO, '')
381
- dir = $3
382
- debug "MOVED IN DIRECTION: #{dir} CMD LEFT:#{cmd}"
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
- score += 2 if match
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
- else
449
- # Just the name, not so good
450
- score += 1 if r.name == name
451
- end
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
- debug "\t ------> #{best[0]} in section #{best[1]}"
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 roomname(line)
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 not b
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
- @rooms[r][:desc] = desc
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 = to
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
- odir = choose_dir(to, from, go, dir)
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
- odir = choose_dir(to, from, go, dir)
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] = c
681
- c.dir = Connection::BOTH
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 e.exitBtext == rgo
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.stop if @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.1
7
- date: 2005-08-21
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/IFMReader.rb
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