ifmapper 0.8.5 → 0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,778 @@
1
+
2
+ require "IFMapper/Map"
3
+
4
+ class FXMap; end
5
+
6
+ #
7
+ # Class that allows creating a map from an Inform source file.
8
+ #
9
+ class InformReader
10
+
11
+ class ParseError < StandardError; end
12
+ class MapError < StandardError; end
13
+
14
+ # Take a quoted Inform string and return a valid ASCII one, replacing
15
+ # Inform's special characters.
16
+ def self.inform_unquote(text)
17
+ return '' unless text
18
+ text.gsub!(/\~/, '"')
19
+ text.gsub!(/\^/, "\n")
20
+ while text =~ /(@@(\d+))/
21
+ text.sub!($1, $2.to_i.chr)
22
+ end
23
+ return text
24
+ end
25
+
26
+ # Temporary classes used to store inform room information
27
+ class InformObject
28
+ attr_reader :name
29
+ attr_accessor :tag, :location, :enterable
30
+
31
+ def name=(x)
32
+ @name = InformReader::inform_unquote(x)
33
+ end
34
+
35
+ def to_s
36
+ "#@name tag:#@tag"
37
+ end
38
+ def initialize()
39
+ @location = []
40
+ @enterable = []
41
+ end
42
+ end
43
+
44
+ class InformDoor
45
+ attr_accessor :location
46
+ attr_accessor :locked
47
+ attr_accessor :tag
48
+ def method_missing(*x)
49
+ end
50
+ def initialize
51
+ @location = []
52
+ end
53
+ end
54
+
55
+ class InformRoom
56
+ attr_reader :name
57
+ attr_accessor :exits, :tag, :darkness
58
+ def to_s
59
+ "#@name tag:#@tag"
60
+ end
61
+ def name=(x)
62
+ @name = InformReader::inform_unquote(x)
63
+ end
64
+ def initialize
65
+ @exits = Array.new(12, nil)
66
+ @darkness = true
67
+ end
68
+ end
69
+
70
+
71
+ DIRECTIONS = {
72
+ 'n_to' => 0,
73
+ 'ne_to' => 1,
74
+ 'e_to' => 2,
75
+ 'se_to' => 3,
76
+ 's_to' => 4,
77
+ 'sw_to' => 5,
78
+ 'w_to' => 6,
79
+ 'nw_to' => 7,
80
+ 'u_to' => 8,
81
+ 'd_to' => 9,
82
+ 'in_to' => 10,
83
+ 'out_to' => 11
84
+ }
85
+
86
+ FUNCTION = /^\[ (\w+);/
87
+
88
+ GO_OBJ = /\b(#{DIRECTIONS.keys.join('|').gsub(/_to/, '_obj')})\s*:/i
89
+
90
+
91
+ # Direction list in order of positioning preference.
92
+ DIRLIST = [ 0, 4, 2, 6, 1, 3, 5, 7 ]
93
+
94
+ NAME = /(?:^|\s+)p?name\s+/i
95
+ DIR_TO = /(?:^|\s+)(#{DIRECTIONS.keys.join('|')})\s+/i
96
+
97
+ DIR = /(?:^|\s+)(#{DIRECTIONS.keys.join('|')})\s+(\w+)/i
98
+ ENTER_DIR = /(?:^|\s+)(#{DIRECTIONS.keys.join('|')})\s+\[;\s*<<\s*Enter\s+(\w+)\s*>>/i
99
+
100
+ attr_reader :map
101
+
102
+ @@debug = 1
103
+ def debug(*x)
104
+ return unless @@debug
105
+ $stdout.puts x
106
+ $stdout.flush
107
+ end
108
+
109
+ #
110
+ # Main parsing loop. We basically parse the file twice to
111
+ # solve dependencies. Yes, this is inefficient, but the alternative
112
+ # was to build a full parser that understands forward dependencies.
113
+ #
114
+ def parse(file)
115
+ # We start map at 0, 0
116
+ @x, @y = [0, 0]
117
+ @room = nil
118
+
119
+ if @map.kind_of?(FXMap)
120
+ @map.options['Edit on Creation'] = false
121
+ @map.window.hide
122
+ end
123
+ @map.section = 0
124
+
125
+ @parsing = nil
126
+ @last_section = 0
127
+ @ignore_first_section = true
128
+ @room_idx = 0
129
+ line_number = 0
130
+
131
+ debug "...Parse... #{file.path}"
132
+ while not file.eof?
133
+ @line = ''
134
+ while not file.eof? and @line == ''
135
+ @line << file.readline()
136
+ @line.sub!( /^\s*!.*$/, '')
137
+ line_number += 1
138
+ end
139
+ # Remove comments at end of line
140
+ @line.sub!( /\s+![^"]*$/, '')
141
+ # Remove starting spaces (if any)
142
+ @line.sub! /^\s+/, ''
143
+ # Replace \n with simple space
144
+ @line.gsub! /\n/, ' '
145
+ next if @line == ''
146
+ full_line = @line.dup
147
+ begin
148
+ parse_line
149
+ rescue ParseError => e
150
+ $stderr.puts
151
+ $stderr.puts "#{e} at #{file.path}, line #{line_number}:"
152
+ $stderr.puts ">>>> #{full_line};"
153
+ $stderr.puts
154
+ end
155
+ end
156
+ debug "...End Parse..."
157
+ end
158
+
159
+
160
+ CLASS = /^class\s+(\w+)/i
161
+ DOOR = /(?:^|\s+)door_to(?:\s+([^,;]*)|$)/i
162
+ INCLUDE = /^#?include\s+"([^"]+)"/i
163
+ PLAYER_TO = /\bplayerto\((\w+)/i
164
+
165
+
166
+ STD_LIB = [
167
+ 'Parser',
168
+ 'VerbLib',
169
+ 'Grammar'
170
+ ]
171
+
172
+
173
+ def find_file(file)
174
+ return file if File.exists?(file)
175
+ @include_dirs.each { |d|
176
+ [ "#{d}/#{file}",
177
+ "#{d}/#{file}.h",
178
+ "#{d}/#{file}.inf", ].each { |full|
179
+ return full if File.exists?(full)
180
+ }
181
+ }
182
+ return nil
183
+ end
184
+
185
+ #
186
+ # Parse a line of file
187
+ #
188
+ def parse_line
189
+ if @line =~ INCLUDE
190
+ name = $1
191
+ unless STD_LIB.include?(name)
192
+ file = find_file(name)
193
+ if file
194
+ File.open(file, 'r') { |f| parse(f) }
195
+ else
196
+ raise ParseError, "Include file #{name} not found"
197
+ end
198
+ end
199
+ end
200
+
201
+ if @line =~ CLASS
202
+ @clas = $1
203
+ debug "CLASS: #@clas"
204
+ if @classes.has_key?(@clas)
205
+ if @obj
206
+ else
207
+ end
208
+ else
209
+ @classes[@clas] = {}
210
+ @tag = @name = nil
211
+ end
212
+ end
213
+
214
+ re = /^(#{@classes.keys.join('|')})(\s+->)?(\s+(\w+))?(\s+"([^"]+)")?(\s+(\w+))?/
215
+ if @line =~ re
216
+ @clas = $1
217
+ prev = $2
218
+ @tag = $4 || $6
219
+ @name = $6
220
+
221
+ loc = $8
222
+ if prev and @room
223
+ loc = @room.tag
224
+ end
225
+
226
+ debug <<"EOF"
227
+ CURRENT ROOM:#@room
228
+ Class : #@clas
229
+ Tag : #@tag
230
+ Name : #@name
231
+ Location: #{loc} #{loc.class}
232
+ EOF
233
+
234
+ @obj = nil
235
+
236
+ c = @classes[@clas]
237
+ if c[:door]
238
+ @obj = InformDoor.new
239
+ @obj.tag = @tag
240
+ @tags[@tag] = @obj
241
+ @doors << @obj
242
+ debug "+++ DOOR"
243
+ elsif loc or c[:scenery] or c[:static]
244
+ debug "+++ OBJECT"
245
+ if @tag
246
+ @obj = InformObject.new()
247
+ @obj.tag = @tag
248
+ @obj.name = @name
249
+ @obj.location << loc
250
+ @tags[@tag] = @obj
251
+ @objects << @obj
252
+ end
253
+ else
254
+ debug "+++ ROOM?"
255
+ @obj = @room = nil
256
+ if @tag and @name
257
+ # We assume we are a room (albeit we could be an obj)
258
+ @room = InformRoom.new
259
+ @room.tag = @tag
260
+ @room.name = @name
261
+ @room.darkness = !c[:light]
262
+ @tags[@tag] = @room
263
+ @rooms << @room
264
+ end
265
+ end
266
+ @before = false
267
+ @go = false
268
+
269
+ end
270
+
271
+ if @line =~ NAME
272
+ # We have an object. Delete last room we created, as it is not one.
273
+ @rooms.delete_if { |r| r.tag == @tag }
274
+ @obj = InformObject.new()
275
+ @obj.tag = @tag
276
+ @obj.name = @name
277
+ @tags[@tag] = @obj
278
+ @objects << @obj
279
+ end
280
+
281
+ if @line =~ FUNCTION
282
+ @functions << $1
283
+ end
284
+
285
+ dirs = @line.scan(DIR_TO) + @line.scan(DIR) + @line.scan(ENTER_DIR)
286
+ if dirs.size > 0
287
+ dirs.each { |d, room|
288
+ dir = DIRECTIONS[d]
289
+ @room.exits[dir] = room
290
+ }
291
+ end
292
+
293
+ if @line =~ /\bbefore\b/i
294
+ @before = true
295
+ end
296
+
297
+ if @line =~ /\bgo\s*:/i and @room and @before
298
+ if @line =~ GO_OBJ
299
+ dir = DIRECTIONS[$1]
300
+ if @line =~ PLAYER_TO
301
+ @room.exits[dir] = $1
302
+ end
303
+ end
304
+ end
305
+
306
+ if @obj.kind_of?(InformObject) and @before
307
+ if @line =~ PLAYER_TO
308
+ @obj.enterable << $1
309
+ end
310
+ end
311
+
312
+ if @tag and @line =~ DOOR
313
+ door = InformDoor.new
314
+ door.location = $1.split(' ')
315
+ door.location += @obj.location if @obj
316
+ door.tag = @tag
317
+ @obj = door
318
+ @tags[@tag] = door
319
+ @doors << door
320
+ @objects.delete(@obj) if @obj and @obj.tag == @tag
321
+ end
322
+
323
+ if @line =~ /\bhas\s+([^,;]+)[,;]/i
324
+ props = $1.split
325
+ props.each { |p|
326
+ if not @tag
327
+ if p[0,1] == '~'
328
+ @classes[@clas][p[1,-1].to_sym] = false
329
+ else
330
+ @classes[@clas][p.to_sym] = true
331
+ end
332
+ else
333
+ if p =~ /locked/ and @doors.size > 0
334
+ @doors[-1].locked = true
335
+ end
336
+ if p =~ /(static|scenery)/ and @obj
337
+ @objects.delete(@obj)
338
+ end
339
+ if @room and p =~ /(\~)?light/
340
+ dark = ($1 == '~')
341
+ @room.darkness = dark
342
+ end
343
+ end
344
+ }
345
+ end
346
+
347
+ if @line =~ /\bfound_in\s+(.*)[,;]?/
348
+ if not @obj
349
+ puts '-' * 78
350
+ puts "#@name -> obj not defined "
351
+ puts '-' * 78
352
+ else
353
+ locs = $1.split
354
+ @obj.location = locs
355
+ debug "#{@obj} #{@obj.location} FOUND_IN: #{locs.join(' ')}"
356
+ end
357
+ end
358
+ end
359
+
360
+
361
+ def shift_link(room, dir)
362
+ idx = dir + 1
363
+ idx = 0 if idx > 7
364
+ while idx != dir
365
+ break if not room[idx]
366
+ idx += 1
367
+ idx = 0 if idx > 7
368
+ end
369
+ if idx != dir
370
+ room[idx] = room[dir]
371
+ room[dir] = nil
372
+ # get position of other room
373
+ ox, oy = Room::DIR_TO_VECTOR[dir]
374
+ c = room[idx]
375
+ if c.roomA == room
376
+ b = c.roomB
377
+ else
378
+ b = c.roomA
379
+ end
380
+ x, y = [b.x, b.y]
381
+ x -= ox
382
+ y -= oy
383
+ dx, dy = Room::DIR_TO_VECTOR[idx]
384
+ @map.shift(x, y, -dx, -dy)
385
+ else
386
+ # raise "Warning. Cannot shift connection for #{room}."
387
+ end
388
+ end
389
+
390
+
391
+ def oneway_link?(a, b)
392
+ # First, check if room already has exit moving towards other room
393
+ a.exits.each_with_index { |e, idx|
394
+ next if not e or e.dir != Connection::AtoB
395
+ roomA = e.roomA
396
+ roomB = e.roomB
397
+ if roomA == a and roomB == b
398
+ return e
399
+ end
400
+ }
401
+ return nil
402
+ end
403
+
404
+
405
+ # Choose a direction to represent up/down/in/out.
406
+ def choose_dir(a, b, go = nil, exitB = nil)
407
+ if go
408
+ rgo = go % 2 == 0? go - 1 : go + 1
409
+ # First, check if room already has exit moving towards other room
410
+ a.exits.each_with_index { |e, idx|
411
+ next if not e or e.stub?
412
+ roomA = e.roomA
413
+ roomB = e.roomB
414
+ if roomA == a and roomB == b
415
+ e.exitAtext = go
416
+ return idx
417
+ elsif roomB == a and roomA == b
418
+ e.exitBtext = go
419
+ return idx
420
+ end
421
+ }
422
+ end
423
+
424
+ # We prefer directions that travel less... so we need to figure
425
+ # out where we start from...
426
+ if b
427
+ x = b.x
428
+ y = b.y
429
+ else
430
+ x = a.x
431
+ y = a.y
432
+ end
433
+ if exitB
434
+ dx, dy = Room::DIR_TO_VECTOR[exitB]
435
+ x += dx
436
+ y += dy
437
+ end
438
+
439
+ # No such luck... Pick a direction.
440
+ best = nil
441
+ bestscore = nil
442
+
443
+ DIRLIST.each { |dir|
444
+ # We prefer straight directions to diagonal ones
445
+ inc = dir % 2 == 1 ? 100 : 140
446
+ score = 1000
447
+ # We prefer directions where both that dir and the opposite side
448
+ # are empty.
449
+ if (not a[dir]) or a[dir].stub?
450
+ score += inc
451
+ score += 4 if a[dir] #attaching to stubs is better
452
+ end
453
+ # rdir = (dir + 4) % 8
454
+ # score += 1 unless a[rdir]
455
+
456
+ # Measure distance for that exit, we prefer shorter
457
+ # paths
458
+ dx, dy = Room::DIR_TO_VECTOR[dir]
459
+ dx = (a.x + dx) - x
460
+ dy = (a.y + dy) - y
461
+ d = dx * dx + dy * dy
462
+ score -= d
463
+ next if bestscore and score <= bestscore
464
+ bestscore = score
465
+ best = dir
466
+ }
467
+
468
+ if not bestscore
469
+ raise "No free exit for choose_dir"
470
+ end
471
+
472
+ return best
473
+ end
474
+
475
+ def new_room(from, to, x, y, dx = 1, dy = 0 )
476
+ elem = @tags[to.tag]
477
+ if elem.kind_of?(InformRoom)
478
+ if not @map.free?(x, y)
479
+ @map.shift(x, y, dx, dy)
480
+ end
481
+ room = @map.new_room(x, y)
482
+ room.name = to.name
483
+ room.darkness = to.darkness
484
+ @tags[to.tag] = room
485
+ return [room, Connection::FREE]
486
+ elsif elem.kind_of?(InformDoor)
487
+ if elem.locked
488
+ type = Connection::LOCKED_DOOR
489
+ else
490
+ type = Connection::CLOSED_DOOR
491
+ end
492
+
493
+ @rooms.each { |o|
494
+ next if @tags[o.tag] == from
495
+ o.exits.each { |e|
496
+ next unless e
497
+ if @tags[e] == elem
498
+ res = new_room( o, o, x, y, dx, dy )
499
+ return [ res[0], type ]
500
+ end
501
+ }
502
+ }
503
+
504
+ # Okay, connecting room is missing. Check door's locations property
505
+ p elem.location
506
+ elem.location.each { |tag|
507
+ next if @tags[tag] == from
508
+ @rooms.each { |o|
509
+ next if o.tag != tag
510
+ res = new_room( o, o, x, y, dx, dy )
511
+ return [ res[0], type ]
512
+ }
513
+ }
514
+
515
+ #raise "error: no room with door #{to.name} #{elem.name}"
516
+ return [nil, nil]
517
+ else
518
+ return [elem, Connection::FREE]
519
+ end
520
+ end
521
+
522
+ def create_room(r, x, y, dx = 1, dy = 0)
523
+ from, = new_room(r, r, x, y)
524
+ debug "CREATE ROOM #{r.name} SET FROM TO: #{from}"
525
+
526
+ r.exits.each_with_index { |e, exit|
527
+ next unless e
528
+ next if e == 'nothing'
529
+ debug "#{r.name} EXIT:#{exit} points to #{e}"
530
+
531
+ to = @tags[e]
532
+ if not to
533
+ next if @functions.include?(e)
534
+ raise "Room #{e} #{e.class} not found." if not to
535
+ end
536
+
537
+ go = c = nil
538
+
539
+ dir = exit
540
+ type = 0
541
+
542
+ # If exit leads to an enterable object, find out where does that
543
+ # enterable object lead to.
544
+ if to.kind_of?(InformObject)
545
+ rooms = to.enterable
546
+ rooms.each { |room|
547
+ next if room == r
548
+ to = @tags[room]
549
+ break
550
+ }
551
+ # Skip it if we are still an object. This means we are just
552
+ # a container, like the phone booth in the Fate game demo.
553
+ next if to.kind_of?(InformObject)
554
+ end
555
+
556
+ if to.kind_of?(InformRoom) or to.kind_of?(InformDoor)
557
+ if dir > 7
558
+ # choose a dir for up/down/in/out
559
+ go = dir - 7
560
+ dir = choose_dir(from, nil, go)
561
+ end
562
+
563
+ dx, dy = Room::DIR_TO_VECTOR[dir]
564
+ x = from.x + dx
565
+ y = from.y + dy
566
+ debug "#{exit} CREATE TO #{from} -> #{to.tag}"
567
+ to, type = new_room(from, to, x, y, dx, dy)
568
+ next if not to
569
+ puts "---- back: #{to.name} #{to.class}"
570
+ else
571
+ if dir > 7
572
+ # choose a dir for up/down/in/out
573
+ go = dir - 7
574
+ dir = choose_dir(from, to, go)
575
+ end
576
+ end
577
+
578
+ odir = (dir + 4) % 8
579
+
580
+ if from[dir]
581
+ c = from[dir]
582
+ if to[odir] == c and c.roomB == from
583
+ debug "LINK TRAVELLED BOTH"
584
+ c.dir = Connection::BOTH
585
+ c.exitBtext = go if go
586
+ next
587
+ else
588
+ debug "#{exit} FROM #{from}->#{to} BLOCKED DIR: #{dir}"
589
+ shift_link(from, dir)
590
+ end
591
+ end
592
+
593
+ # Check we don't have a connection already
594
+ if to[odir]
595
+ c = to[odir]
596
+ debug "#{from} #{dir} -> #{to} dir:#{odir} filled. Swap..."
597
+
598
+ # We need to change odir to something else
599
+ rgo = 0
600
+ if go
601
+ rgo = go % 2 == 0? go - 1 : go + 1
602
+ end
603
+
604
+ # First, check if we have a dangling one-way link going to->from
605
+ # If we do, we use it.
606
+ c = oneway_link?(from, to)
607
+ if not c
608
+ odir = choose_dir(to, from, rgo, dir)
609
+ debug "Swapped to #{odir}"
610
+ else
611
+ debug "FOUND LINK #{c} -- filling it."
612
+ idx = from.exits.index(c)
613
+ from[idx] = nil
614
+ from[dir] = c
615
+ c.dir = Connection::BOTH
616
+ c.exitBtext = go
617
+ end
618
+ else
619
+ debug "to[odir] empty."
620
+ # First, check if we have a dangling one-way link going to->from
621
+ # If we do, we use it.
622
+ c = oneway_link?(to, from)
623
+ if c
624
+ debug "FOUND LINK #{c} -- filling it."
625
+ idx = from.exits.index(c)
626
+ from[idx] = nil
627
+ from[dir] = c
628
+ c.dir = Connection::BOTH
629
+ c.exitBtext = go if go
630
+ end
631
+ end
632
+
633
+ if not c
634
+ debug "NEW LINK #{from} #{dir} to #{to} #{odir}"
635
+ begin
636
+ c = @map.new_connection(from, dir, to, odir)
637
+ c.exitAtext = go if go
638
+ c.dir = Connection::AtoB
639
+ c.type = type
640
+ rescue Section::ConnectionError
641
+ end
642
+ end
643
+ }
644
+
645
+ return r
646
+ end
647
+
648
+ #
649
+ # Create all the stuff we found
650
+ #
651
+ def create
652
+ @rooms.each { |r| create_room(r, 0, 0) }
653
+ @rooms = []
654
+
655
+ # Add objects to rooms
656
+ @objects.each { |obj|
657
+ obj.location.each { |loc|
658
+ r = @tags[loc]
659
+ next unless r and r.kind_of?(Room)
660
+ r.objects << obj.name + "\n"
661
+ }
662
+ }
663
+ end
664
+
665
+
666
+ if RUBY_PLATFORM =~ /win/
667
+ SEP = ';'
668
+ else
669
+ SEP = ':'
670
+ end
671
+
672
+ #
673
+ # Bring up the Inform properties window, to allow user to change
674
+ # settings
675
+ #
676
+ def properties
677
+ decor = DECOR_TITLE|DECOR_BORDER
678
+
679
+ dlg = FXDialogBox.new( @map.window.parent, "Inform Settings", decor )
680
+ mainFrame = FXVerticalFrame.new(dlg,
681
+ FRAME_SUNKEN|FRAME_THICK|
682
+ LAYOUT_FILL_X|LAYOUT_FILL_Y)
683
+
684
+ frame = FXHorizontalFrame.new(mainFrame, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
685
+
686
+ FXLabel.new(frame, "Include Dirs: ", nil, 0, LAYOUT_FILL_X)
687
+ inc = FXTextField.new(frame, 80, nil, 0, LAYOUT_FILL_ROW)
688
+ inc.text = @include_dirs.join(SEP)
689
+
690
+ buttons = FXHorizontalFrame.new(mainFrame,
691
+ LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|
692
+ PACK_UNIFORM_WIDTH)
693
+ # Accept
694
+ FXButton.new(buttons, "&Accept", nil, dlg, FXDialogBox::ID_ACCEPT,
695
+ FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
696
+
697
+ # Cancel
698
+ FXButton.new(buttons, "&Cancel", nil, dlg, FXDialogBox::ID_CANCEL,
699
+ FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
700
+ if dlg.execute != 0
701
+ @include_dirs = inc.text.split(SEP)
702
+ return true
703
+ end
704
+ return false
705
+ end
706
+
707
+
708
+
709
+ def set_include_dirs
710
+ # Try to find inform(.exe) in path.
711
+ paths = ENV['PATH'].split(SEP)
712
+ paths.each { |p|
713
+ next if not File.directory?(p)
714
+ Dir.foreach(p) { |x|
715
+ if x =~ /^inform(.exe)?$/i
716
+ @include_dirs << p
717
+ @include_dirs << p + "/Base"
718
+ @include_dirs << p + "/Contrib"
719
+ @include_dirs << p + "/../Contrib"
720
+ break
721
+ end
722
+ }
723
+ }
724
+ end
725
+
726
+ def initialize(file, map = Map.new('Inform Map'))
727
+ debug "Initialize"
728
+ @classes = { 'Object' => {} }
729
+ @tags = {}
730
+ @map = map
731
+ @objects = []
732
+ @doors = []
733
+ @functions = []
734
+ @rooms = []
735
+
736
+ @include_dirs = [File.dirname(file)]
737
+ set_include_dirs
738
+
739
+
740
+ debug "Get properties"
741
+ if @map.kind_of?(FXMap)
742
+ return unless properties
743
+ end
744
+
745
+ debug "Start parsing #{file}"
746
+ File.open(file) { |f|
747
+ parse(f)
748
+ }
749
+ debug "Done parsing #{file}"
750
+ debug "Rooms: #{@rooms.size}"
751
+ debug "Doors: #{@doors.size}"
752
+ debug "Objects: #{@objects.size}"
753
+
754
+ create
755
+ debug "Done creating #{file}"
756
+
757
+ if @map.kind_of?(FXMap)
758
+ @map.filename = file.sub(/\.inf$/i, '.map')
759
+ # @map.navigation = true
760
+ @map.modified = false
761
+ @map.window.show
762
+ end
763
+ @objects = nil
764
+ @tags = nil # save some memory by clearing the tag list
765
+ @rooms = nil # and room list
766
+ end
767
+ end
768
+
769
+
770
+ if $0 == __FILE__
771
+ p "Opening file '#{ARGV[0]}'"
772
+ BEGIN {
773
+ $LOAD_PATH << 'C:\Windows\Escritorio\IFMapper\lib'
774
+ }
775
+
776
+ require "IFMapper/Map"
777
+ InformReader.new(ARGV[0])
778
+ end