ifmapper 0.9.6 → 0.9.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -26,7 +26,7 @@ class TranscriptReader
26
26
  TAKE = /^(take|get)\s+(a\s+|the\s+)?(.*)/i
27
27
  DROP = /^(drop|leave)\s+()/i
28
28
  STARTUP = /(^[A-Z]+$|Copyright|\([cC]\)\s*\d|Trademark|Release|Version|[Ss]erial [Nn]umber|Written by)/
29
- DARKNESS = /^dark(ness)?$|^in the dark$|^It is pitch black|^It is too dark to see anything|^You stumble around in the dark/i
29
+ DARKNESS = /^dark(ness)?$|^in the dark$|^a dark place$|^It is pitch black|^It is too dark to see anything|^You stumble around in the dark/i
30
30
  DEAD = /(You die|You have died|You are dead)/i
31
31
  YES = /^y(es)/i
32
32
 
@@ -68,12 +68,14 @@ class TranscriptReader
68
68
  ]
69
69
 
70
70
  # remove things like (on the bed)
71
- NAME_REMOVE = /(\s+\(.+\)|,\s+[io]n\s+[^\,\.]+)/
72
- NAME_INVALID = /--|[:;\*\[\]\|\+\=!\.\?\000]/
71
+ PREPOSITION = "(?:in|on|under|behind|inside|\w+ing)"
72
+ NAME_REMOVE = /(\s+\(#{PREPOSITION}\s+.+\)|,\s+#{PREPOSITION}\s+[^\,\.]+)/
73
+ NAME_INVALID = /--|[:;\*\[\]\|\+\=!\.\?\000<>]/
73
74
  SALUT = '(Mr|Mr?s|Miss|Jr|Sr|St|Dr|Ave|Inc)'
74
75
  SALUTATIONS = /\b#{SALUT}\./
75
76
  NAME_MAXWORDS = 20
76
- NAME_MAXUNCAP = 4 # so that lowercase "room" "end" "of" will be accepted
77
+ # word list that may be uncapitalized
78
+ NAME_UNCAP = /^(?:of|on|to|with|by|a|in|the|under)$/
77
79
 
78
80
  # Default room description recognition parameters.
79
81
  DESC_MINWORDS = 20
@@ -890,10 +892,6 @@ class TranscriptReader
890
892
  # Qucik check for word characters
891
893
  return false unless line =~ /\w/
892
894
 
893
- # Check word count (if too many, not a room)
894
- words = line.split(' ')
895
- return false if words.size > NAME_MAXWORDS
896
-
897
895
  # Check if we start line with uncapitalized words or symbols
898
896
  return false if line =~ /^[ a-z\/\\\-\(\)']/
899
897
 
@@ -902,6 +900,10 @@ class TranscriptReader
902
900
  return false if line =~ /^[A-Z\d,\.\/\-"'\s]+$/ or line =~ /\s\s/ or
903
901
  line =~ /^".*"$/ or line =~ /^"[^"]+$/ or line =~ /^\d+\)/
904
902
 
903
+ # Check word count (if too many, not a room)
904
+ words = line.split(' ')
905
+ return false if words.size > NAME_MAXWORDS
906
+
905
907
  return false if not all_capitals and words.size > 6
906
908
 
907
909
  # If not, check all words of 4 chars or more are capitalized
@@ -909,7 +911,7 @@ class TranscriptReader
909
911
  # (which means a diagram)
910
912
  num = 0
911
913
  words.each { |w|
912
- return false if all_capitals and w =~ /^[a-z]/ and w.size > NAME_MAXUNCAP
914
+ return false if all_capitals and w =~ /^[a-z]/ and w !~ NAME_UNCAP
913
915
  if w.size <= 2
914
916
  num += 1
915
917
  return false if num > 2
Binary file
Binary file
Binary file
data/maps/devours.map ADDED
Binary file
data/maps/djinni.map ADDED
Binary file
data/maps/party.map ADDED
Binary file
data/maps/pkgirl.map CHANGED
Binary file
Binary file
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: ifmapper
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.9.6
7
- date: 2005-09-19
6
+ version: 0.9.7
7
+ date: 2005-10-08
8
8
  summary: Interactive Fiction Mapping Tool.
9
9
  require_paths:
10
10
  - lib
@@ -30,35 +30,36 @@ files:
30
30
  - IFMapper.rbw
31
31
  - lib/IFMapper/FXMap.rb
32
32
  - lib/IFMapper/Map.rb
33
+ - lib/IFMapper/FXSpline.rb
33
34
  - lib/IFMapper/FXRoom.rb
34
35
  - lib/IFMapper/FXSectionDialogBox.rb
35
- - lib/IFMapper/FXMapperWindow.rb
36
36
  - lib/IFMapper/Section.rb
37
37
  - lib/IFMapper/FXConnection.rb
38
38
  - lib/IFMapper/FXMapColorBox.rb
39
39
  - lib/IFMapper/IFMReader.rb
40
- - lib/IFMapper/IFMWriter.rb
41
40
  - lib/IFMapper/FXWarningBox.rb
41
+ - lib/IFMapper/IFMWriter.rb
42
42
  - lib/IFMapper/FXMapperSettings.rb
43
+ - lib/IFMapper/AStar.rb
44
+ - lib/IFMapper/FXMapperWindow.rb
43
45
  - lib/IFMapper/Connection.rb
44
- - lib/IFMapper/MapPrinting.rb
45
46
  - lib/IFMapper/FXDCPostscript.rb
47
+ - lib/IFMapper/MapPrinting.rb
46
48
  - lib/IFMapper/FXDCPrint.rb
47
49
  - lib/IFMapper/Room.rb
48
50
  - lib/IFMapper/PDFMapExporter.rb
49
51
  - lib/IFMapper/TranscriptReader.rb
50
52
  - lib/IFMapper/FXMapDialogBox.rb
51
- - lib/IFMapper/FXSpline.rb
52
53
  - lib/IFMapper/InformReader.rb
53
- - lib/IFMapper/FXMapFileDialog.rb
54
54
  - lib/IFMapper/InformWriter.rb
55
55
  - lib/IFMapper/FXSection.rb
56
56
  - lib/IFMapper/TADSReader.rb
57
- - lib/IFMapper/InformReaderOld.rb
57
+ - lib/IFMapper/GUEReader.rb
58
+ - lib/IFMapper/FXMapFileDialog.rb
58
59
  - lib/IFMapper/TADSWriter.rb
59
60
  - lib/IFMapper/FXRoomDialogBox.rb
60
61
  - lib/IFMapper/FXConnectionDialogBox.rb
61
- - lib/IFMapper/AStar.rb
62
+ - lib/IFMapper/MapReader.rb
62
63
  - lib/IFMapper/TranscriptDialogBox.rb
63
64
  - lib/IFMapper/FXRoomList.rb
64
65
  - lib/IFMapper/FXAboutDialogBox.rb
@@ -152,6 +153,13 @@ files:
152
153
  - maps/heroes.map
153
154
  - maps/photograph.map
154
155
  - maps/drift3.map
156
+ - maps/party.map
157
+ - maps/devours.map
158
+ - maps/djinni.map
159
+ - maps/A New Life.map
160
+ - maps/History Repeating.map
161
+ - maps/Unforgotten.map
162
+ - maps/splashdown.map
155
163
  - icons/filenew.png
156
164
  - icons/fileopen.png
157
165
  - icons/filesave.png
@@ -1,778 +0,0 @@
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