ifmapper 0.9.6 → 0.9.7

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