ifmapper 0.9.6 → 0.9.7

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.
@@ -35,7 +35,7 @@ class Section
35
35
  # Return the min and max coordinates of all rooms in page
36
36
  #
37
37
  def min_max_rooms
38
- return [0, 0] if @rooms.empty?
38
+ return [[0, 0],[0, 0]] if @rooms.empty?
39
39
 
40
40
  minXY = [ @rooms[0].x, @rooms[0].y ]
41
41
  maxXY = minXY.dup
@@ -122,10 +122,10 @@ class Section
122
122
  # Verify rooms exist in section (ie. don't allow links across
123
123
  # sections)
124
124
  if not @rooms.include?(roomA)
125
- raise ConnectionError, "Room #{roomA} not in section #{self}"
125
+ raise ConnectionError, "Room '#{roomA}' not in section #{self}"
126
126
  end
127
127
  if roomB and not @rooms.include?(roomB)
128
- raise ConnectionError, "Room #{roomB} not in section #{self}"
128
+ raise ConnectionError, "Room '#{roomB}' not in section #{self}"
129
129
  end
130
130
 
131
131
  c = Connection.new( roomA, roomB )
@@ -167,6 +167,7 @@ class Section
167
167
  def initialize()
168
168
  @rooms = []
169
169
  @connections = []
170
+ @name = ''
170
171
  end
171
172
 
172
173
  protected
@@ -189,9 +190,9 @@ EOF
189
190
 
190
191
  if roomA[exitA]
191
192
  if not @connections.include?(roomA[exitA])
192
- raise ConnectionError, "roomA exit #{exitA} for #{roomA} filled but not in section"
193
+ raise ConnectionError, "roomA exit #{exitA} for '#{roomA}' filled but not in section"
193
194
  end
194
- raise ConnectionError, "roomA exit #{exitA} for #{roomA} is filled"
195
+ raise ConnectionError, "roomA exit #{exitA} for '#{roomA}' is filled"
195
196
  end
196
197
 
197
198
  roomA[exitA] = c
@@ -211,7 +212,7 @@ EOF
211
212
 
212
213
  if roomB and roomB[exitB] and roomB[exitB] != c
213
214
  roomA[exitA] = nil
214
- raise ConnectionError, "roomB exit #{exitB} for #{roomB} is filled"
215
+ raise ConnectionError, "roomB exit #{exitB} for #{roomB} is filled with #{roomB[exitB]}"
215
216
  end
216
217
  roomB[exitB] = c if roomB
217
218
 
@@ -1,16 +1,25 @@
1
1
 
2
- require "IFMapper/Map"
2
+ require 'IFMapper/MapReader'
3
+
4
+
5
+ # Take a quoted TADS string and return a valid ASCII one, replacing
6
+ # TADS's special characters.
7
+ module TADSUnquote
8
+ def unquote(text)
9
+ return '' unless text
10
+ text.gsub!(/\\'/, "'") # restore quotes
11
+ text.gsub!(/\\"/, '"') # restore quotes
12
+ text.gsub!(/<<.*>>/, '') # remove embedded functions
13
+ text.gsub!(/<\/?q>/, '"') # Change quotes
14
+ return text
15
+ end
16
+ end
3
17
 
4
- class FXMap; end
5
18
 
6
19
  #
7
20
  # Class that allows creating a map from an TADS source file.
8
21
  #
9
- class TADSReader
10
-
11
- class ParseError < StandardError; end
12
- class MapError < StandardError; end
13
-
22
+ class TADSReader < MapReader
14
23
 
15
24
  # TADS 3 directional properties need to be spelled fully
16
25
  DIRECTIONS = {
@@ -41,8 +50,6 @@ class TADSReader
41
50
  # Equal sign (TADS supports C or Pascal-like =)
42
51
  EQ = '\s*(?:=|\:=)\s*'
43
52
 
44
- # Direction list in order of positioning preference.
45
- DIRLIST = [ 0, 4, 2, 6, 1, 3, 5, 7 ]
46
53
 
47
54
  DIR_EQ = "(#{DIRECTIONS.keys.join('|')})#{EQ}"
48
55
  DIR_TO = /(?:^|\s+)#{DIR_EQ}/
@@ -51,7 +58,7 @@ class TADSReader
51
58
  DIR_INSELF = /(?:^|\s+)#{DIR_EQ}\(\s*[\d\w]+\.isIn\(\s*self\s*\)\s*\?\s*([\d\w]+)/
52
59
  DIR_MSG = /(?:^|\s+)(#{DIRECTIONS.keys.join('|')})\s*\:\s*TravelMessage\s*\{\s*\->\s*(\w+)/
53
60
 
54
- ENTER_DIR = //i # needed?
61
+ ENTER_DIR = /(?:^|\s+)(#{DIRECTIONS.keys.join('|')})\s*:\s*.*<<replaceAction\(Enter\s*,\s*(\w+)/i
55
62
 
56
63
  OBJLOCATION = /(?:^|\s+)(?:(?:destination|location)#{EQ}(\w+)|@(\w+)|locationList#{EQ}\[([\w\s,]+)\])/
57
64
  OBJNAME = /(?:^|\s+)name#{EQ}(?:'#{SQ}'|\(\s*described\s*\?\s*'#{SQ}')/
@@ -76,84 +83,47 @@ class TADSReader
76
83
  STD_LIB = [
77
84
  'adv3.h',
78
85
  'en_us.h',
86
+ 'bignum.h',
87
+ 'array.h',
88
+ 'tok.h',
89
+ 'bytearr.h',
90
+ 'charset.h',
91
+ 'dict.h',
92
+ 'reflect.h',
93
+ 'gramprod.h',
94
+ 'systype.h',
95
+ 'tads.h',
96
+ 'tadsgen.h',
97
+ 'tadsio.h',
98
+ 't3.h',
99
+ 'vector.h',
100
+ 'file.h',
101
+ 't3test.h',
102
+ 'strcomp.h',
79
103
  ]
80
104
 
81
105
 
82
- # Take a quoted TADS string and return a valid ASCII one, replacing
83
- # TADS's special characters.
84
- def self.unquote(text)
85
- return '' unless text
86
- text.gsub!(/\\'/, "'") # restore quotes
87
- text.gsub!(/\\"/, '"') # restore quotes
88
- text.gsub!(/<<.*>>/, '') # remove embedded functions
89
- text.gsub!(/<\/?q>/, '"') # Change quotes
90
- return text
91
- end
92
-
93
- # Temporary classes used to store inform room information
94
- class TADSObject
95
- attr_reader :name
96
- attr_accessor :tag, :location, :enterable
97
-
98
- def name=(x)
99
- @name = TADSReader::unquote(x)
100
- end
106
+ attr_reader :map
101
107
 
102
- def to_s
103
- "#@name tag:#@tag"
104
- end
105
108
 
106
- def method_missing(*a)
107
- end
108
109
 
109
- def initialize(location)
110
- if location
111
- @location = Array[*location]
112
- else
113
- @location = []
114
- end
115
- @enterable = []
116
- end
117
- end
110
+ include TADSUnquote
118
111
 
119
- class TADSDoor
120
- attr_accessor :location, :locked, :connector, :tag
121
- def method_missing(*x)
122
- end
123
- def initialize
124
- @location = []
125
- end
112
+ class TADSRoom < MapRoom
113
+ include TADSUnquote
126
114
  end
127
115
 
128
- class TADSRoom
129
- attr_reader :name
130
- attr_accessor :exits, :tag, :light, :desc
131
- def to_s
132
- "#@name tag:#@tag"
133
- end
134
- def num_exits
135
- return @exits.nitems
136
- end
137
- def name=(x)
138
- @name = TADSReader::unquote(x)
139
- end
140
- def method_missing(*x)
141
- end
142
- def initialize
143
- @desc = ''
144
- @light = true
145
- @exits = Array.new(12, nil)
146
- end
116
+ class TADSObject < MapObject
117
+ include TADSUnquote
147
118
  end
148
119
 
149
120
 
150
- attr_reader :map
121
+ def new_room
122
+ super(TADSRoom)
123
+ end
151
124
 
152
- @@debug = nil
153
- def debug(*x)
154
- return unless @@debug
155
- $stdout.puts x
156
- $stdout.flush
125
+ def new_obj(loc = nil)
126
+ super(loc, TADSObject)
157
127
  end
158
128
 
159
129
  #
@@ -198,10 +168,11 @@ class TADSReader
198
168
  begin
199
169
  parse_line
200
170
  rescue ParseError, MapError => e
201
- $stderr.puts
202
- $stderr.puts "#{e} at #{file.path}, line #{line_number}:"
203
- $stderr.puts ">>>> #{full_line};"
204
- $stderr.puts
171
+ message = "#{e}.\nat #{file.path}, line #{line_number}:\n>>>> #{full_line};\n"
172
+ raise message
173
+ rescue => e
174
+ message = "#{e}\n#{e.backtrace}"
175
+ raise message
205
176
  end
206
177
  end
207
178
  debug "...End Parse..."
@@ -209,26 +180,6 @@ class TADSReader
209
180
 
210
181
 
211
182
 
212
- def new_room
213
- # We assume we are a room (albeit we could be an obj)
214
- @room = TADSRoom.new
215
- @room.tag = @tag
216
- @room.name = @name
217
- @room.desc = @desc
218
- @tags[@tag] = @room
219
- @rooms << @room
220
- end
221
-
222
- def new_obj(loc = nil)
223
- debug "+++ OBJECT #@name"
224
- @obj = TADSObject.new(loc)
225
- @obj.tag = @tag
226
- @obj.name = @name
227
- @tags[@tag] = @obj
228
- @objects << @obj
229
- end
230
-
231
-
232
183
  def find_file(file)
233
184
  return file if File.exists?(file)
234
185
  @include_dirs.each { |d|
@@ -265,7 +216,7 @@ class TADSReader
265
216
  if file
266
217
  File.open(file, 'r') { |f| parse(f) }
267
218
  else
268
- raise ParseError, "Include file #{name} not found"
219
+ raise ParseError, "Include file '#{name}' not found"
269
220
  end
270
221
  end
271
222
  end
@@ -307,18 +258,29 @@ class TADSReader
307
258
  return
308
259
  end
309
260
 
261
+ if @gameid and @line =~ /name\s*=\s*'(#{SQ})'/
262
+ @map.name = $1
263
+ end
310
264
 
311
265
  # TADS3 definition is like:
312
266
  # [+] [TAG:] Classes ['adjective nouns'] 'Name' @location
313
267
  re = /^#{PLUS}#{TAG}#{CLS}#{NOMS}#{NAME}#{LOC}/
314
268
  if @line =~ re
315
269
 
270
+
316
271
  prev = $1
317
272
  @name = [$5, $4]
318
273
  @tag = $2
319
274
  @clas = $3 # can be several classes
320
275
  @in_desc = false
321
276
 
277
+ if @tag
278
+ if @clas == "GameID"
279
+ @gameid = true
280
+ else
281
+ @gameid = false
282
+ end
283
+ end
322
284
 
323
285
  loc = $6
324
286
  if prev and @room
@@ -344,36 +306,28 @@ class TADSReader
344
306
  elsif @clas =~ /\bRoomConnector\b/
345
307
  debug "+++ CONNECTOR TAG: #@tag"
346
308
  @desc = ''
347
- @obj = TADSDoor.new
309
+ new_door(loc)
348
310
  @obj.connector = true
349
- @obj.tag = @tag
350
- @tags[@tag] = @obj
351
- @doors << @obj
352
311
  elsif @clas =~ /\b(?:(?:Hidden|Secret)?Door|ThroughPassage|PathPassage|TravelWithMessage|Stairway(?:Up|Down))\b/
353
312
  @desc = ''
354
313
  @name = @name[0] || @name[1]
355
314
  @tag = @name if not @tag
356
315
  debug "+++ DOOR #@tag"
357
316
  if @clas =~ /\s+->\s*(\w+)/
358
- debug "\tmatching side: #{@tag} -> #$1"
359
317
  # this is the other side of the door... find matching side
360
318
  @obj = @tags[$1]
361
319
  if not @obj
362
- @obj = TADSDoor.new
363
- @obj.tag = @tag
320
+ new_door(loc)
364
321
  @tags[$1] = @obj
322
+ else
323
+ @tags[@tag] = @obj
324
+ @obj.location << loc if loc
365
325
  end
366
- @tags[@tag] = @obj
367
- @obj.location << loc if loc
368
326
  else
369
- @obj = @tags[@tag] || TADSDoor.new
327
+ new_door(loc) if @tag
370
328
  @obj.locked = true if @clas =~ /\bLockable(WithKey)?\b/
371
- @obj.tag = @tag
372
- @obj.location = [loc] if loc
373
- @tags[@tag] = @obj
374
- @doors << @obj
375
329
  end
376
- @obj.connector = true if @clas =~ /Passage|Stairway/
330
+ @obj.connector = true if @clas !~ /\b(?:Hidden|Secret)?Door\b/
377
331
  elsif @clas =~ /\b(?:Thing|Food|Person)\b/
378
332
  @obj = nil
379
333
  @desc = ''
@@ -381,7 +335,19 @@ class TADSReader
381
335
  @name = '' if @name =~ /\//
382
336
  @tag = @name if not @tag
383
337
  new_obj(loc) if @tag
338
+ elsif @clas =~ /\bEnterable\b/ and @tag
339
+ @desc = ''
340
+ @name = @name[0] || @name[1]
341
+ @name = '' if @name =~ /\//
342
+ @tag = @name if not @tag
343
+ new_obj(loc)
344
+ if @clas =~ /\s+->\s*(\w+)/
345
+ @obj.enterable << $1
346
+ end
384
347
  else
348
+ if @tag
349
+ @obj = nil
350
+ end
385
351
  @name = (@name[0] || @name[1] || @tag)
386
352
  end
387
353
 
@@ -396,19 +362,20 @@ class TADSReader
396
362
  end
397
363
 
398
364
  if @obj
399
-
400
365
  if @obj.name == '' and @line =~ /^\s*#{NOMS}#{NAME}\s*$/
401
366
  name = $2 || $1
402
367
  @obj.name = name
403
368
  end
404
369
  @obj.name = $1 || $2 if @line =~ OBJNAME
405
370
  if @line =~ OBJLOCATION
406
- if $1
407
- locs = $1.split(/\s*,\s*/)
371
+ loc = $1 || $2 || $3
372
+ if loc
373
+ locs = loc.split(/\s*,\s*/)
408
374
  @obj.location += locs
375
+ @obj.location.uniq!
409
376
  end
410
377
  end
411
- @obj.location << $1 if @obj.connector and @line =~ CONNECTOR
378
+ @obj.location << loc if @obj.connector and @line =~ CONNECTOR
412
379
  end
413
380
 
414
381
  if @room and @line =~ ROOMNAME
@@ -422,385 +389,23 @@ class TADSReader
422
389
  end
423
390
 
424
391
  # dirs = @line.scan(DIR_TO) + @line.scan(DIR) + @line.scan(DIR_MSG)
425
- dirs = @line.scan(DIR) + @line.scan(DIR_MSG) + @line.scan(DIR_OPEN) + @line.scan(DIR_INSELF)
426
- if dirs.size > 0
427
- dirs.each { |d, room|
428
- next if not room or room == 'nil' or room == 'noTravel'
429
- dir = DIRECTIONS[d]
430
- @room.exits[dir] = room
431
- }
432
- end
433
-
434
- end
435
-
436
-
437
- def shift_link(room, dir)
438
- idx = dir + 1
439
- idx = 0 if idx > 7
440
- while idx != dir
441
- break if not room[idx]
442
- idx += 1
443
- idx = 0 if idx > 7
444
- end
445
- if idx != dir
446
- room[idx] = room[dir]
447
- room[dir] = nil
448
- # get position of other room
449
- ox, oy = Room::DIR_TO_VECTOR[dir]
450
- c = room[idx]
451
- if c.roomA == room
452
- b = c.roomB
453
- else
454
- b = c.roomA
455
- end
456
- x, y = [b.x, b.y]
457
- x -= ox
458
- y -= oy
459
- dx, dy = Room::DIR_TO_VECTOR[idx]
460
- @map.shift(x, y, -dx, -dy)
461
- else
462
- # raise "Warning. Cannot shift connection for #{room}."
463
- end
464
- end
465
-
466
-
467
- def oneway_link?(a, b)
468
- # First, check if room already has exit moving towards other room
469
- a.exits.each_with_index { |e, idx|
470
- next if not e or e.dir != Connection::AtoB
471
- roomA = e.roomA
472
- roomB = e.roomB
473
- if roomA == a and roomB == b
474
- return e
475
- end
476
- }
477
- return nil
478
- end
479
-
480
-
481
- # Choose a direction to represent up/down/in/out.
482
- def choose_dir(a, b, go = nil, exitB = nil)
483
- if go
484
- rgo = go % 2 == 0? go - 1 : go + 1
485
- # First, check if room already has exit moving towards other room
486
- a.exits.each_with_index { |e, idx|
487
- next if not e
488
- roomA = e.roomA
489
- roomB = e.roomB
490
- if roomA == a and roomB == b
491
- e.exitAtext = go
492
- return idx
493
- elsif roomB == a and roomA == b
494
- e.exitBtext = go
495
- return idx
496
- end
497
- }
498
- end
499
-
500
- # We prefer directions that travel less... so we need to figure
501
- # out where we start from...
502
- if b
503
- x = b.x
504
- y = b.y
505
- else
506
- x = a.x
507
- y = a.y
508
- end
509
- if exitB
510
- dx, dy = Room::DIR_TO_VECTOR[exitB]
511
- x += dx
512
- y += dy
513
- end
514
-
515
- # No such luck... Pick a direction.
516
- best = nil
517
- bestscore = nil
518
-
519
- DIRLIST.each { |dir|
520
- # We prefer straight directions to diagonal ones
521
- inc = dir % 2 == 1 ? 100 : 140
522
- score = 1000
523
- # We prefer directions where both that dir and the opposite side
524
- # are empty.
525
- if (not a[dir]) or a[dir].stub?
526
- score += inc
527
- score += 4 if a[dir] #attaching to stubs is better
528
- end
529
- # rdir = (dir + 4) % 8
530
- # score += 1 unless a[rdir]
531
-
532
- # Measure distance for that exit, we prefer shorter
533
- # paths
534
- dx, dy = Room::DIR_TO_VECTOR[dir]
535
- dx = (a.x + dx) - x
536
- dy = (a.y + dy) - y
537
- d = dx * dx + dy * dy
538
- score -= d
539
- next if bestscore and score <= bestscore
540
- bestscore = score
541
- best = dir
542
- }
543
-
544
- if not bestscore
545
- raise "No free exit for choose_dir"
546
- end
547
-
548
- return best
549
- end
550
-
551
- def make_room(to, x, y, dx = 1, dy = 0)
552
- if not @map.free?(x, y)
553
- @map.shift(x, y, dx, dy)
554
- end
555
- room = @map.new_room(x, y)
556
- room.name = to.name
557
- desc = to.desc
558
- desc.gsub!(/[\t\n]/, ' ')
559
- desc.squeeze!(' ')
560
- room.desc = TADSReader::unquote(desc)
561
- room.darkness = !to.light
562
- @tags[to.tag] = room
563
- return room
564
- end
565
-
566
- def get_exit(from, to, x, y, dx = 1, dy = 0 )
567
- elem = @tags[to.tag]
568
- if elem.kind_of?(TADSRoom)
569
- room = create_room(to, x, y, dx, dy)
570
- return [room, Connection::FREE]
571
- elsif elem.kind_of?(TADSDoor)
572
- if elem.connector
573
- type = Connection::FREE
574
- elsif elem.locked
575
- type = Connection::LOCKED_DOOR
576
- else
577
- type = Connection::CLOSED_DOOR
578
- end
579
-
580
- @rooms.each { |o|
581
- next if @tags[o.tag] == from
582
- o.exits.each { |e|
583
- next unless e
584
- if @tags[e] == elem
585
- res = create_room( o, x, y, dx, dy )
586
- return [ res, type ]
587
- end
392
+ if @room
393
+ dirs = ( @line.scan(DIR) + @line.scan(DIR_MSG) +
394
+ @line.scan(DIR_OPEN) + @line.scan(DIR_INSELF) +
395
+ @line.scan(ENTER_DIR) )
396
+ if dirs.size > 0
397
+ dirs.each { |d, room|
398
+ next if not room or room == 'nil' or room =~ /^noTravel/
399
+ dir = DIRECTIONS[d]
400
+ @room.exits[dir] = room
588
401
  }
589
- }
590
-
591
- # Okay, connecting room is missing. Check door's locations property
592
- elem.location.each { |tag|
593
- next if @tags[tag] == from
594
- @rooms.each { |o|
595
- next if o.tag != tag
596
- res = create_room( o, x, y, dx, dy )
597
- return [ res, type ]
598
- }
599
- }
600
-
601
- #raise MapError, "error: no room with door #{to.name} #{elem.name}"
602
- return [nil, nil]
603
- else
604
- return [elem, Connection::FREE]
605
- end
606
- end
607
-
608
- def create_room(r, x, y, dx = 2, dy = 0)
609
- return @tags[r.tag] if @tags[r.tag].kind_of?(Room)
610
- from, = make_room(r, x, y, dx, dy)
611
- debug "CREATE ROOM #{r.name} TAG:#{r.tag}"
612
-
613
- r.exits.each_with_index { |e, exit|
614
- next unless e
615
- next if e == 'nothing' or e == '0'
616
- debug "#{r.name} EXIT:#{exit} points to #{e}"
617
-
618
- to = @tags[e]
619
- if not to
620
- next if @functions.include?(e)
621
- if not to
622
- $stderr.puts "Exit to #{e} (#{e.class}) not found, ignored."
623
- next
624
- end
625
- end
626
-
627
- go = c = nil
628
-
629
- dir = exit
630
- type = 0
631
-
632
- # # If exit leads to an enterable object, find out where does that
633
- # # enterable object lead to.
634
- # if to.kind_of?(TADSObject)
635
- # rooms = to.enterable
636
- # rooms.each { |room|
637
- # next if room == r
638
- # to = @tags[room]
639
- # break
640
- # }
641
- # # Skip it if we are still an object. This means we are just
642
- # # a container, like the phone booth in the Fate game demo.
643
- # next if to.kind_of?(TADSObject)
644
- # end
645
-
646
- if to.kind_of?(TADSRoom) or to.kind_of?(TADSDoor)
647
- if dir > 7
648
- # choose a dir for up/down/in/out
649
- go = dir - 7
650
- dir = choose_dir(from, nil, go)
651
- end
652
-
653
- dx, dy = Room::DIR_TO_VECTOR[dir]
654
- x = from.x + dx
655
- y = from.y + dy
656
- debug "#{exit} CREATE TO #{from} -> #{to.tag}"
657
- to, type = get_exit(from, to, x, y, dx, dy)
658
- next if not to
659
- end
660
-
661
- if exit > 7
662
- # choose a dir for up/down/in/out
663
- go = exit - 7
664
- dir = choose_dir(from, to, go)
665
- end
666
-
667
- b = @rooms.find { |r2| r2.tag == e }
668
- odir = nil
669
- odir = b.exits.rindex(r.tag) if b
670
- odir = (dir + 4) % 8 if not odir or odir > 7
671
-
672
- if from[dir]
673
- c = from[dir]
674
- if to.exits.rindex(c) and c.roomB == from
675
- debug "LINK TRAVELLED BOTH"
676
- c.dir = Connection::BOTH
677
- c.exitBtext = go if go
678
- next
679
- else
680
- debug "#{exit} FROM #{from}->#{to} BLOCKED DIR: #{dir}"
681
- shift_link(from, dir)
682
- end
683
- end
684
-
685
- # Check we don't have a connection already
686
- if to[odir]
687
- c = to[odir]
688
- debug "#{from} #{dir} -> #{to} dir:#{odir} filled. Swap..."
689
-
690
- # We need to change odir to something else
691
- rgo = 0
692
- if go
693
- rgo = go % 2 == 0? go - 1 : go + 1
694
- end
695
-
696
- # First, check if we have a dangling one-way link going to->from
697
- # If we do, we use it.
698
- c = oneway_link?(from, to)
699
- if not c
700
- odir = choose_dir(to, from, rgo, dir)
701
- debug "Swapped to #{odir}"
702
- else
703
- debug "FOUND LINK #{c} -- filling it."
704
- idx = from.exits.index(c)
705
- from[idx] = nil
706
- from[dir] = c
707
- c.dir = Connection::BOTH
708
- c.exitBtext = go if go
709
- end
710
- else
711
- debug "to[odir] empty."
712
- # First, check if we have a dangling one-way link going to->from
713
- # If we do, we use it.
714
- c = oneway_link?(to, from)
715
- if c
716
- debug "FOUND LINK #{c} -- filling it."
717
- idx = from.exits.index(c)
718
- from[idx] = nil
719
- from[dir] = c
720
- c.dir = Connection::BOTH
721
- c.exitBtext = go if go
722
- end
723
- end
724
-
725
- if not c
726
- debug "NEW LINK #{from} #{dir} to #{to} #{odir}"
727
- begin
728
- c = @map.new_connection(from, dir, to, odir)
729
- c.exitAtext = go if go
730
- c.dir = Connection::AtoB
731
- c.type = type
732
- rescue Section::ConnectionError
733
- end
734
402
  end
735
- }
736
-
737
- return from
738
- end
739
-
740
- #
741
- # Create all the stuff we found
742
- #
743
- def create
744
- @rooms = @rooms.sort_by { |r| r.num_exits }
745
- @rooms.reverse!
403
+ end
746
404
 
747
- @rooms.each { |r|
748
- min, max = @map.sections[@map.section].min_max_rooms
749
- create_room(r, max[0] + 2, 0)
750
- }
751
- @rooms = []
752
-
753
- # Add objects to rooms
754
- @objects.each { |obj|
755
- obj.location.each { |loc|
756
- r = @tags[loc]
757
- next unless r and r.kind_of?(Room)
758
- r.objects << obj.name + "\n"
759
- }
760
- }
761
405
  end
762
406
 
763
407
 
764
- if RUBY_PLATFORM =~ /win/
765
- SEP = ';'
766
- else
767
- SEP = ':'
768
- end
769
408
 
770
- #
771
- # Bring up the TADS properties window, to allow user to change
772
- # settings
773
- #
774
- def properties
775
- decor = DECOR_TITLE|DECOR_BORDER
776
-
777
- dlg = FXDialogBox.new( @map.window.parent, "TADS Settings", decor )
778
- mainFrame = FXVerticalFrame.new(dlg,
779
- FRAME_SUNKEN|FRAME_THICK|
780
- LAYOUT_FILL_X|LAYOUT_FILL_Y)
781
-
782
- frame = FXHorizontalFrame.new(mainFrame, LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
783
-
784
- FXLabel.new(frame, "Include Dirs: ", nil, 0, LAYOUT_FILL_X)
785
- inc = FXTextField.new(frame, 80, nil, 0, LAYOUT_FILL_ROW)
786
- inc.text = @include_dirs.join(SEP)
787
-
788
- buttons = FXHorizontalFrame.new(mainFrame,
789
- LAYOUT_SIDE_BOTTOM|LAYOUT_FILL_X|
790
- PACK_UNIFORM_WIDTH)
791
- # Accept
792
- FXButton.new(buttons, "&Accept", nil, dlg, FXDialogBox::ID_ACCEPT,
793
- FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
794
-
795
- # Cancel
796
- FXButton.new(buttons, "&Cancel", nil, dlg, FXDialogBox::ID_CANCEL,
797
- FRAME_RAISED|FRAME_THICK|LAYOUT_RIGHT|LAYOUT_CENTER_Y)
798
- if dlg.execute != 0
799
- @include_dirs = inc.text.split(SEP)
800
- return true
801
- end
802
- return false
803
- end
804
409
 
805
410
  def parse_makefile(file)
806
411
  dir = File.dirname(file)
@@ -835,26 +440,7 @@ class TADSReader
835
440
  }
836
441
  end
837
442
 
838
- def initialize(file, map = Map.new('TADS Map'))
839
- debug "Initialize"
840
- @classes = { 'Object' => {} }
841
- @tags = {}
842
- @map = map
843
- @objects = []
844
- @doors = []
845
- @functions = []
846
- @rooms = []
847
-
848
- @include_dirs = [File.dirname(file)]
849
- set_include_dirs
850
-
851
-
852
- debug "Get properties"
853
- if @map.kind_of?(FXMap)
854
- return unless properties
855
- end
856
-
857
-
443
+ def read_file(file)
858
444
  if file =~ /.t3m/
859
445
  files = parse_makefile(file)
860
446
  else
@@ -862,28 +448,14 @@ class TADSReader
862
448
  end
863
449
 
864
450
  files.each_with_index { |file, idx|
865
- debug "Start parsing #{file}"
866
- File.open(file) { |f|
867
- parse(f)
868
- }
869
- debug "Done parsing #{file}"
451
+ super(file)
870
452
  }
453
+ end
871
454
 
872
- puts "Rooms: #{@rooms.size}"
873
- puts "Doors/Connectors: #{@doors.size}"
874
- puts "Objects: #{@objects.size}"
875
-
876
- create
877
- debug "Done creating #{file}"
878
-
879
- if @map.kind_of?(FXMap)
880
- @map.filename = file.sub(/\.t$/i, '.map')
881
- @map.options['Location Description'] = true
882
- @map.window.show
883
- end
884
- @objects = nil
885
- @tags = nil # save some memory by clearing the tag list
886
- @rooms = nil # and room list
455
+ def initialize(file, map = Map.new('TADS Map'))
456
+ debug "Initialize"
457
+ @classes = { 'Object' => {} }
458
+ super
887
459
  end
888
460
  end
889
461