ifmapper 0.9.5 → 0.9.6

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