ifmapper 0.9.5 → 0.9.6

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,3 +1,69 @@
1
+ v0.9.6 What's new:
2
+
3
+ - IFM exporting had gotten broken around v0.9 due to a refactoring
4
+ bug. Fixed.
5
+
6
+ - CTRL selection was never quite working as advertised. Now it
7
+ properly does toggle selecting of rooms/connections.
8
+
9
+ - Minor improvement to the automapper. Now places that have Dr.,
10
+ St., Ave. and Inc. in them will be recognized as locations.
11
+ Previously, they were ignored due to the period.
12
+
13
+ - The automapper will now correctly parse objects from take commands
14
+ when the response is something like:
15
+ You take the pencil from the bag.
16
+ Previously, the object was considered to be 'pencil from the bag'
17
+ instead of just 'pencil'.
18
+
19
+ - Slight improvement to the automapper room description
20
+ identification. When comparing descriptions and a perfect match
21
+ or submatch of the description cannot be found against a room, all
22
+ words in that room description will be compared for a
23
+ potential match. A room will be matched as already present if
24
+ at least 20 words match (they also have to be in the same order).
25
+ However, if multiple rooms happen to match 20 words, then the room
26
+ with more words matched will be considered as the correct match.
27
+ This improvement helps with locations that have identical
28
+ descriptions but that perhaps only change the exit paths.
29
+
30
+ - I bug fixed the problem with TADS transcripts with the automapper
31
+ crashing it. This was supposed to be fixed in 0.9.5 but I had
32
+ inadvertedly reverted the fix before release.
33
+
34
+ - Added a new mode to Automapper of transcripts. The new
35
+ mode is called Capitalized and helps map rooms where the room name
36
+ uses a single capitalized sentence, like:
37
+ Women's change room
38
+ Western closet
39
+ instead of the more standard:
40
+ Women's Change Room
41
+ Western Closet
42
+ This format seems somewhat popular among IFComp entries, which are
43
+ probably trying to follow Infocom's format, but do so incorrectly.
44
+
45
+ - Added a new ADRIFT mode to Automapper. This mode helps map
46
+ ADRIFT games, which have some weird form of transcripts, lacking a
47
+ prompt. Tested with The PK Girl mainly.
48
+
49
+ - TADS3 source code reader is now much improved.
50
+ It recognizes PathPassages, TravelMessage and noTravel
51
+ exits properly.
52
+ It does not consider a missing room as a fatal error and
53
+ will properly find names of rooms when room line is split into
54
+ multiple lines.
55
+ It will also display passage and stairway exits properly (previously,
56
+ they were considered door exits).
57
+ Also, TADS3 reader can now properly parse a t3m Makefile for
58
+ sources.
59
+ You should now be able to map the big TADS3 demo game
60
+ Return to Ditch Day from source, which previously would run
61
+ into some issues.
62
+
63
+ - TADS and Inform readers now use a slightly different algorithm for
64
+ laying out rooms. This new algorithm results in smaller maps and
65
+ usually less complex exits failing.
66
+
1
67
  v0.9.5 What's new:
2
68
 
3
69
  - IFMapper now looks for Fox1.4 and 1.2, in that order. Note that
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.9.5'
5
+ spec.version = '0.9.6'
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/'
@@ -17,5 +17,5 @@ EOF
17
17
  spec.extra_rdoc_files = ["HISTORY.txt", "TODO.txt", "IFMapper.gemspec"]
18
18
  spec.has_rdoc = true
19
19
  spec.rubyforge_project = 'ifmapper'
20
- spec.required_ruby_version = '>= 1.6.8'
20
+ spec.required_ruby_version = '>= 1.8.0'
21
21
  end
@@ -345,6 +345,7 @@ class FXConnection < Connection
345
345
  # Draw any exit text if available (exit text is 'U', 'D', 'I', 'O', etc)
346
346
  #
347
347
  def draw_exit_text(dc, zoom)
348
+ return if zoom < 0.5
348
349
  if @exitText[0] != 0
349
350
  dir = @room[0].exits.index(self)
350
351
  x, y = @room[0].corner(self, zoom, dir)
@@ -875,10 +875,10 @@ class FXMap < Map
875
875
  w = x2 - x1
876
876
  h = y2 - y1
877
877
 
878
- x1 = (x1 / WW).floor
879
- y1 = (y1 / HH).floor
880
- x2 = (x2 / WW).ceil
881
- y2 = (y2 / HH).ceil
878
+ x1 = ((x1 - WS_2) / WW).floor
879
+ y1 = ((y1 - HS_2) / HH).floor
880
+ x2 = ((x2 - WS_2) / WW).ceil
881
+ y2 = ((y2 - HS_2) / HH).ceil
882
882
 
883
883
  @sections[@section].rooms.each { |r|
884
884
  if r.x >= x1 and r.x <= x2 and
@@ -1156,12 +1156,13 @@ class FXMap < Map
1156
1156
  draw
1157
1157
  return
1158
1158
  else
1159
- if event.state & SHIFTMASK == 0
1159
+ if event.state & SHIFTMASK == 0 and
1160
+ event.state & CONTROLMASK == 0
1160
1161
  clear_selection
1161
1162
  end
1162
1163
  # Select the stuff
1163
1164
  selection.update_properties(self)
1164
- if event.state & CONTROLMASK == 0
1165
+ if event.state & CONTROLMASK != 0
1165
1166
  selection.selected ^= true # toggle selection
1166
1167
  else
1167
1168
  selection.selected = true
@@ -1478,10 +1479,8 @@ class FXMap < Map
1478
1479
  end
1479
1480
 
1480
1481
  def cannot_automap(why)
1481
- p '----CANNOT AUTOMAP'
1482
1482
  w = FXWarningBox.new(@window, "Cannot automap.\n#{why}")
1483
1483
  w.execute
1484
- p '----CANNOT AUTOMAP AFTER EXECUTE'
1485
1484
  end
1486
1485
 
1487
1486
 
@@ -1965,7 +1964,7 @@ class FXMap < Map
1965
1964
  def export_ifm(file)
1966
1965
  require 'IFMapper/IFMWriter'
1967
1966
  file += '.ifm' if file !~ /\.ifm$/
1968
- IFMWriter.new(map, file)
1967
+ IFMWriter.new(self, file)
1969
1968
  end
1970
1969
 
1971
1970
 
@@ -2048,6 +2047,7 @@ class FXMap < Map
2048
2047
  begin
2049
2048
  @automap = TranscriptReader.new(self, file)
2050
2049
  @automap.properties(true)
2050
+ @automap.start
2051
2051
  rescue Errno::EACCES, Errno::ENOENT => e
2052
2052
  dlg = FXWarningBox.new(@window, "Cannot open transcript\n#{e}")
2053
2053
  dlg.execute
@@ -2058,7 +2058,6 @@ class FXMap < Map
2058
2058
  dlg.execute
2059
2059
  raise
2060
2060
  end
2061
- @automap.start
2062
2061
  create_pathmap
2063
2062
  draw
2064
2063
  update_title
@@ -8,7 +8,7 @@ class FXMapFileDialog < FXFileDialog
8
8
  @@last_path = nil
9
9
 
10
10
  KNOWN_EXTENSIONS = [
11
- "Map Files (*.map,*.ifm,*.inf,*.t)",
11
+ "Map Files (*.map,*.ifm,*.inf,*.t,*.t3m)",
12
12
  "All Files (*)",
13
13
  ]
14
14
 
@@ -59,7 +59,7 @@ require 'IFMapper/FXRoomList'
59
59
  class FXMapperWindow < FXMainWindow
60
60
 
61
61
  PROGRAM_NAME = "Interactive Fiction Mapper"
62
- VERSION = '0.9.5'
62
+ VERSION = '0.9.6'
63
63
  AUTHOR = "Gonzalo Garramuno"
64
64
  TITLE = "#{PROGRAM_NAME} v#{VERSION} - Written by #{AUTHOR}"
65
65
 
@@ -84,7 +84,7 @@ class FXMapperWindow < FXMainWindow
84
84
  begin
85
85
  IFMReader.new(file, map)
86
86
  rescue => e
87
- return e
87
+ return "#{e} #{e.backtrace}"
88
88
  end
89
89
  return map
90
90
  end
@@ -94,7 +94,7 @@ class FXMapperWindow < FXMainWindow
94
94
  begin
95
95
  TADSReader.new(file, map)
96
96
  rescue => e
97
- return e
97
+ return "#{e} #{e.backtrace}"
98
98
  end
99
99
  return map
100
100
  end
@@ -104,7 +104,7 @@ class FXMapperWindow < FXMainWindow
104
104
  begin
105
105
  InformReader.new(file, map)
106
106
  rescue => e
107
- return e
107
+ return "#{e} #{e.backtrace}"
108
108
  end
109
109
  return map
110
110
  end
@@ -172,13 +172,14 @@ class FXMapperWindow < FXMainWindow
172
172
  tmp = open_ifm(file, map)
173
173
  elsif file =~ /\.inf$/i
174
174
  tmp = open_inform(file, map)
175
- elsif file =~ /\.t$/i
175
+ elsif file =~ /\.t$/i or file =~ /\.t3m$/
176
176
  tmp = open_tads(file, map)
177
177
  else
178
178
  tmp = open_map(file)
179
179
  end
180
180
 
181
181
  if not tmp.kind_of?(Map) and not tmp.kind_of?(FXMap)
182
+ $stderr.puts tmp
182
183
  status "Could not load '#{file}'. Error: #{tmp}."
183
184
  if make_new_map
184
185
  if map.close_cb
@@ -755,6 +756,43 @@ class FXMapperWindow < FXMainWindow
755
756
  @search.show
756
757
  end
757
758
 
759
+ #
760
+ # Find task in map
761
+ #
762
+ def find_desc_in_map(s, m, e)
763
+ map = current_map
764
+ return unless map
765
+
766
+ re = /#{s.text}/
767
+ matches = []
768
+ (0...map.sections.size).each { |p|
769
+ map.sections[p].rooms.each { |r|
770
+ next unless r.desc =~ re
771
+ matches.push( [p, r] )
772
+ }
773
+ }
774
+ idx = @search.index
775
+ @search.index = matches.size-1 if idx >= matches.size
776
+ hilite_matches(map, matches, re, @search.index)
777
+ end
778
+
779
+ #
780
+ # Find description in map
781
+ #
782
+ def find_desc_in_map_cb(s, m, e)
783
+ map = current_map
784
+ return unless map
785
+
786
+ title = "Find In Description In Map"
787
+ if not @search
788
+ @search = FXSearchDialogBox.new(self)
789
+ end
790
+ @search.proc = method(:find_desc_in_map)
791
+ @search.title = title
792
+ @search.text = ''
793
+ @search.show
794
+ end
795
+
758
796
  #
759
797
  # Pop-up color preferences
760
798
  #
@@ -803,12 +841,12 @@ class FXMapperWindow < FXMainWindow
803
841
 
804
842
  def about_cb(sender, id, event )
805
843
  FXAboutDialogBox.new(self, "About This Software...", <<"EOF").execute
806
- #{TITLE} - #{VERSION}
844
+ #{PROGRAM_NAME} - #{VERSION}
845
+ Written by Gonzalo Garramuno.
807
846
 
808
847
  FXRuby Version: #{Fox::fxrubyversion}
809
848
 
810
849
  A WYSIWYG mapping tool for interactive fiction.
811
- Written by Gonzalo Garramuno.
812
850
 
813
851
  ggarra@advancedsl.com.ar
814
852
  EOF
@@ -899,6 +937,8 @@ EOF
899
937
  cmd.connect(SEL_COMMAND, method(:find_object_in_map_cb))
900
938
  cmd = FXMenuCommand.new(submenu, "&Task in Map\tAlt-T\tFind Location with a Task in the Map")
901
939
  cmd.connect(SEL_COMMAND, method(:find_task_in_map_cb))
940
+ cmd = FXMenuCommand.new(submenu, "&Keyword in Descriptions\tAlt-D\tFind Location with Description Keyword in the Map")
941
+ cmd.connect(SEL_COMMAND, method(:find_desc_in_map_cb))
902
942
  FXMenuCascade.new(editmenu, "Search", nil, submenu)
903
943
 
904
944
  # Complex Connection
@@ -1189,7 +1229,8 @@ EOF
1189
1229
 
1190
1230
  cmd = FXMenuCommand.new(helpmenu, "&Resource Code", nil)
1191
1231
  cmd.connect(SEL_COMMAND) {
1192
- file = FXMapFileDialog.new(self, "Resource a Ruby File").filename
1232
+ file = FXMapFileDialog.new(self, "Resource a Ruby File",
1233
+ ['Ruby File (*.rb)']).filename
1193
1234
  if file != ''
1194
1235
  begin
1195
1236
  Kernel.load file
@@ -10,7 +10,7 @@ class FXRoomDialogBox < FXDialogBox
10
10
  def copy_to()
11
11
  @room.name = @name.text
12
12
  @room.objects = @objects.text
13
- @room.objects.gsub!(/[\.,\t]+/, "\n")
13
+ @room.objects.gsub!(/[,\t]+/, "\n")
14
14
  @room.tasks = @tasks.text
15
15
  @room.darkness = (@darkness.checkState == 1)
16
16
  @room.desc = @desc.text
@@ -13,7 +13,7 @@ class InformReader
13
13
 
14
14
  # Take a quoted Inform string and return a valid ASCII one, replacing
15
15
  # Inform's special characters.
16
- def self.inform_unquote(text)
16
+ def self.unquote(text)
17
17
  return '' unless text
18
18
  text.gsub!(/\~/, '"')
19
19
  text.gsub!(/\^/, "\n")
@@ -29,7 +29,7 @@ class InformReader
29
29
  attr_accessor :tag, :location, :enterable
30
30
 
31
31
  def name=(x)
32
- @name = InformReader::inform_unquote(x)
32
+ @name = InformReader::unquote(x)
33
33
  end
34
34
 
35
35
  def to_s
@@ -67,7 +67,10 @@ class InformReader
67
67
  "#@name tag:#@tag"
68
68
  end
69
69
  def name=(x)
70
- @name = InformReader::inform_unquote(x)
70
+ @name = InformReader::unquote(x)
71
+ end
72
+ def num_exits
73
+ return @exits.nitems
71
74
  end
72
75
  def method_missing(*x)
73
76
  end
@@ -492,20 +495,25 @@ EOF
492
495
  return best
493
496
  end
494
497
 
495
- def make_room(from, to, x, y, dx = 1, dy = 0 )
498
+ def make_room(to, x, y, dx = 1, dy = 0)
499
+ if not @map.free?(x, y)
500
+ @map.shift(x, y, dx, dy)
501
+ end
502
+ room = @map.new_room(x, y)
503
+ room.name = to.name
504
+ desc = to.desc
505
+ desc.gsub!(/[\t\n]/, ' ')
506
+ desc.squeeze!(' ')
507
+ room.desc = InformReader::unquote(desc)
508
+ room.darkness = !to.light
509
+ @tags[to.tag] = room
510
+ return room
511
+ end
512
+
513
+ def get_exit(from, to, x, y, dx = 1, dy = 0 )
496
514
  elem = @tags[to.tag]
497
515
  if elem.kind_of?(InformRoom)
498
- if not @map.free?(x, y)
499
- @map.shift(x, y, dx, dy)
500
- end
501
- room = @map.new_room(x, y)
502
- room.name = to.name
503
- desc = to.desc
504
- desc.gsub!(/[\t\n]/, ' ')
505
- desc.squeeze!(' ')
506
- room.desc = InformReader::inform_unquote(desc)
507
- room.darkness = !to.light
508
- @tags[to.tag] = room
516
+ room = create_room(to, x, y, dx, dy)
509
517
  return [room, Connection::FREE]
510
518
  elsif elem.kind_of?(InformDoor)
511
519
  if elem.locked
@@ -519,8 +527,8 @@ EOF
519
527
  o.exits.each { |e|
520
528
  next unless e
521
529
  if @tags[e] == elem
522
- res = make_room( o, o, x, y, dx, dy )
523
- return [ res[0], type ]
530
+ res = create_room( o, x, y, dx, dy )
531
+ return [ res, type ]
524
532
  end
525
533
  }
526
534
  }
@@ -530,8 +538,8 @@ EOF
530
538
  next if @tags[tag] == from
531
539
  @rooms.each { |o|
532
540
  next if o.tag != tag
533
- res = make_room( o, o, x, y, dx, dy )
534
- return [ res[0], type ]
541
+ res = create_room( o, x, y, dx, dy )
542
+ return [ res, type ]
535
543
  }
536
544
  }
537
545
 
@@ -542,8 +550,9 @@ EOF
542
550
  end
543
551
  end
544
552
 
545
- def create_room(r, x, y, dx = 1, dy = 0)
546
- from, = make_room(r, r, x, y)
553
+ def create_room(r, x, y, dx = 2, dy = 0)
554
+ return @tags[r.tag] if @tags[r.tag].kind_of?(Room)
555
+ from, = make_room(r, x, y, dx, dy)
547
556
  debug "CREATE ROOM #{r.name} SET FROM TO: #{from}"
548
557
 
549
558
  r.exits.each_with_index { |e, exit|
@@ -587,7 +596,7 @@ EOF
587
596
  x = from.x + dx
588
597
  y = from.y + dy
589
598
  debug "#{exit} CREATE TO #{from} -> #{to.tag}"
590
- to, type = make_room(from, to, x, y, dx, dy)
599
+ to, type = get_exit(from, to, x, y, dx, dy)
591
600
  next if not to
592
601
  end
593
602
 
@@ -667,14 +676,20 @@ EOF
667
676
  end
668
677
  }
669
678
 
670
- return r
679
+ return from
671
680
  end
672
681
 
673
682
  #
674
683
  # Create all the stuff we found
675
684
  #
676
685
  def create
677
- @rooms.each { |r| create_room(r, 0, 0) }
686
+ @rooms = @rooms.sort_by { |r| r.num_exits }
687
+ @rooms.reverse!
688
+
689
+ @rooms.each { |r|
690
+ min, max = @map.sections[@map.section].min_max_rooms
691
+ create_room(r, max[0] + 2, 0)
692
+ }
678
693
  @rooms = []
679
694
 
680
695
  # Add objects to rooms
@@ -781,7 +796,6 @@ EOF
781
796
 
782
797
  if @map.kind_of?(FXMap)
783
798
  @map.filename = file.sub(/\.inf$/i, '.map')
784
- @map.navigation = true
785
799
  @map.options['Location Description'] = true
786
800
  @map.window.show
787
801
  end
data/lib/IFMapper/Room.rb CHANGED
@@ -76,9 +76,7 @@ class Room
76
76
  # Return the number of exits present in room
77
77
  #
78
78
  def num_exits
79
- num = 0
80
- @exits.each { |e| num += 1 if e }
81
- return num
79
+ return @exits.nitems
82
80
  end
83
81
 
84
82
  #