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 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