ifmapper 1.0.0 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. data/HISTORY.txt +648 -627
  2. data/IFMapper.gemspec +29 -28
  3. data/IFMapper.rbw +31 -31
  4. data/TODO.txt +8 -7
  5. data/bin/IFMapper +31 -31
  6. data/docs/en/index.html +0 -0
  7. data/docs/en/start.html +3 -2
  8. data/docs/en/start.html~ +516 -0
  9. data/docs/es/index.html +0 -0
  10. data/docs/es/start.html +13 -14
  11. data/docs/es/start.html~ +1280 -0
  12. data/docs/images/IFMapper_main.gif +0 -0
  13. data/docs/images/automap.gif +0 -0
  14. data/docs/images/complex_connection.gif +0 -0
  15. data/docs/images/connection.gif +0 -0
  16. data/docs/images/connection_menu.gif +0 -0
  17. data/docs/images/room_description.gif +0 -0
  18. data/docs/images/room_small.gif +0 -0
  19. data/icons/copy.png +0 -0
  20. data/icons/cut.png +0 -0
  21. data/icons/filenew.png +0 -0
  22. data/icons/fileopen.png +0 -0
  23. data/icons/filesave.png +0 -0
  24. data/icons/filesaveas.png +0 -0
  25. data/icons/help.png +0 -0
  26. data/icons/kill.png +0 -0
  27. data/icons/nextpage.png +0 -0
  28. data/icons/paste.png +0 -0
  29. data/icons/prevpage.png +0 -0
  30. data/icons/printicon.png +0 -0
  31. data/icons/redo.png +0 -0
  32. data/icons/room_e.gif +0 -0
  33. data/icons/room_e.xpm +0 -0
  34. data/icons/room_n.gif +0 -0
  35. data/icons/room_n.xpm +0 -0
  36. data/icons/room_ne.gif +0 -0
  37. data/icons/room_ne.xpm +0 -0
  38. data/icons/room_nw.gif +0 -0
  39. data/icons/room_nw.xpm +0 -0
  40. data/icons/room_s.gif +0 -0
  41. data/icons/room_s.xpm +0 -0
  42. data/icons/room_se.gif +0 -0
  43. data/icons/room_se.xpm +0 -0
  44. data/icons/room_sw.gif +0 -0
  45. data/icons/room_sw.xpm +0 -0
  46. data/icons/room_w.gif +0 -0
  47. data/icons/room_w.xpm +0 -0
  48. data/icons/saveas.png +0 -0
  49. data/icons/undo.png +0 -0
  50. data/icons/winapp.png +0 -0
  51. data/icons/zoom.png +0 -0
  52. data/lib/IFMapper/AStar.rb +250 -250
  53. data/lib/IFMapper/Connection.rb +202 -202
  54. data/lib/IFMapper/FXAboutDialogBox.rb +32 -32
  55. data/lib/IFMapper/FXConnection.rb +364 -364
  56. data/lib/IFMapper/FXConnectionDialogBox.rb +124 -124
  57. data/lib/IFMapper/FXDCPostscript.rb +404 -404
  58. data/lib/IFMapper/FXDCPrint.rb +15 -15
  59. data/lib/IFMapper/FXItemList.rb +108 -0
  60. data/lib/IFMapper/FXMap.rb +2147 -2116
  61. data/lib/IFMapper/FXMapColorBox.rb +88 -88
  62. data/lib/IFMapper/FXMapDialogBox.rb +127 -127
  63. data/lib/IFMapper/FXMapFileDialog.rb +34 -34
  64. data/lib/IFMapper/FXMapperSettings.rb +206 -205
  65. data/lib/IFMapper/FXMapperWindow.rb +1592 -1571
  66. data/lib/IFMapper/FXPDFMapExporterOptionsDialogBox.rb +46 -0
  67. data/lib/IFMapper/FXRoom.rb +263 -263
  68. data/lib/IFMapper/FXRoomDialogBox.rb +159 -159
  69. data/lib/IFMapper/FXRoomList.rb +95 -95
  70. data/lib/IFMapper/FXSearchDialogBox.rb +51 -51
  71. data/lib/IFMapper/FXSection.rb +33 -33
  72. data/lib/IFMapper/FXSectionDialogBox.rb +38 -38
  73. data/lib/IFMapper/FXSpline.rb +52 -52
  74. data/lib/IFMapper/FXWarningBox.rb +51 -50
  75. data/lib/IFMapper/GUEReader.rb +445 -445
  76. data/lib/IFMapper/IFMReader.rb +584 -584
  77. data/lib/IFMapper/IFMWriter.rb +245 -227
  78. data/lib/IFMapper/Inform7Writer.rb +579 -573
  79. data/lib/IFMapper/InformReader.rb +478 -478
  80. data/lib/IFMapper/InformWriter.rb +364 -359
  81. data/lib/IFMapper/Map.rb +202 -200
  82. data/lib/IFMapper/MapPrinting.rb +162 -162
  83. data/lib/IFMapper/MapReader.rb +900 -900
  84. data/lib/IFMapper/PDFMapExporter.rb +526 -483
  85. data/lib/IFMapper/Room.rb +153 -151
  86. data/lib/IFMapper/Section.rb +234 -234
  87. data/lib/IFMapper/TADSReader.rb +474 -471
  88. data/lib/IFMapper/TADSWriter.rb +375 -370
  89. data/lib/IFMapper/TranscriptDialogBox.rb +0 -0
  90. data/lib/IFMapper/TranscriptReader.rb +1361 -1359
  91. data/lib/IFMapper/locales/en/Messages.rb +446 -435
  92. data/lib/IFMapper/locales/es/Messages.rb +451 -440
  93. data/lib/IFMapper/locales/es/Messages_iso-8859-1.rb +455 -440
  94. data/lib/IFMapper/locales/es/runme.sh +3 -3
  95. data/maps/A New Life.map b/data/maps/A New → Life.map +0 -0
  96. data/maps/AMFV.map +0 -0
  97. data/maps/AllRoads.map +0 -0
  98. data/maps/Aotearoa.map +0 -0
  99. data/maps/Bronze.map +0 -0
  100. data/maps/Bureaucracy.ifm +0 -0
  101. data/maps/Bureaucracy.map +0 -0
  102. data/maps/CityOfSecrets.map +0 -0
  103. data/maps/DDIV.map +0 -0
  104. data/maps/Following_A_Star.map +0 -0
  105. data/maps/Heated.map +0 -0
  106. data/maps/Heroine.map +0 -0
  107. data/maps/History Repeating.map b/data/maps/History → Repeating.map +0 -0
  108. data/maps/Hollywood_Hijinx.ifm +0 -0
  109. data/maps/Janitor.map +0 -0
  110. data/maps/Jigsaw.ifm +0 -0
  111. data/maps/Jigsaw.map +0 -0
  112. data/maps/LGOP.ifm +0 -0
  113. data/maps/Mercy.ifm +0 -0
  114. data/maps/Ninjas_Fate.map +0 -0
  115. data/maps/Pen_and_Paint.map +0 -0
  116. data/maps/Planetfall.ifm +0 -0
  117. data/maps/Planetfall.map +0 -0
  118. data/maps/Plundered_Hearts.ifm +0 -0
  119. data/maps/QuietEvening.map +0 -0
  120. data/maps/Ralph.ifm +0 -0
  121. data/maps/Reliques_of_Tolti_Alph.map +0 -0
  122. data/maps/Revolution.map +0 -0
  123. data/maps/Robots_of_Dawn.ifm +0 -0
  124. data/maps/SavoirFare.map +0 -0
  125. data/maps/Seastalker.ifm +0 -0
  126. data/maps/Seastalker.map +0 -0
  127. data/maps/Sherlock.ifm +0 -0
  128. data/maps/SoFar.ifm +0 -0
  129. data/maps/Starcross.ifm +0 -0
  130. data/maps/Suspended.ifm +0 -0
  131. data/maps/Tangle.map +0 -0
  132. data/maps/The_Lost_Sheep.map +0 -0
  133. data/maps/Unforgotten.map +0 -0
  134. data/maps/Warbler's Nest.map +0 -0
  135. data/maps/Warbler's_Nest.map +0 -0
  136. data/maps/Westminster_Abbey.map +0 -0
  137. data/maps/WinterWonderland.map +0 -0
  138. data/maps/Wishbringer.ifm +0 -0
  139. data/maps/Wishbringer2.ifm +0 -0
  140. data/maps/Zork1.ifm +0 -0
  141. data/maps/Zork2.ifm +0 -0
  142. data/maps/Zork3.ifm +0 -0
  143. data/maps/Zork_Zero.ifm +0 -0
  144. data/maps/anchor.ifm +0 -0
  145. data/maps/anchor.map +0 -0
  146. data/maps/atrox.ifm +0 -0
  147. data/maps/awaken.ifm +0 -0
  148. data/maps/babel.ifm +0 -0
  149. data/maps/balances.map +0 -0
  150. data/maps/ballerina.map +0 -0
  151. data/maps/bear.map +0 -0
  152. data/maps/bluechairs.map +0 -0
  153. data/maps/break_in.map +0 -0
  154. data/maps/bse.ifm +0 -0
  155. data/maps/building.map +0 -0
  156. data/maps/change.ifm +0 -0
  157. data/maps/christminster.map +0 -0
  158. data/maps/curses.ifm +0 -0
  159. data/maps/curves.ifm +0 -0
  160. data/maps/deadline.map +0 -0
  161. data/maps/delusions.map +0 -0
  162. data/maps/devours.map +0 -0
  163. data/maps/distress.map +0 -0
  164. data/maps/djinni.map +0 -0
  165. data/maps/dreamhold.map +0 -0
  166. data/maps/drift3.map +0 -0
  167. data/maps/eas.map +0 -0
  168. data/maps/eas2.map +0 -0
  169. data/maps/eas3.map +0 -0
  170. data/maps/edifice.ifm +0 -0
  171. data/maps/fallacy.map +0 -0
  172. data/maps/frozen.ifm +0 -0
  173. data/maps/gamlet.map +0 -0
  174. data/maps/glow.ifm +0 -0
  175. data/maps/guilty_bastards.map +0 -0
  176. data/maps/heist.map +0 -0
  177. data/maps/heroes.map +0 -0
  178. data/maps/inhumane.map +0 -0
  179. data/maps/kaged.map +0 -0
  180. data/maps/library.ifm +0 -0
  181. data/maps/lurkinghorror.map +0 -0
  182. data/maps/metamorphoses.map +0 -0
  183. data/maps/mindelec.ifm +0 -0
  184. data/maps/minster.ifm +0 -0
  185. data/maps/mite.map +0 -0
  186. data/maps/moonmist.map +0 -0
  187. data/maps/muldoon_legacy.map +0 -0
  188. data/maps/muse.ifm +0 -0
  189. data/maps/paperchase.ifm +0 -0
  190. data/maps/party.map +0 -0
  191. data/maps/pawn.map +0 -0
  192. data/maps/photograph.map +0 -0
  193. data/maps/pkgirl.map +0 -0
  194. data/maps/pytho.map +0 -0
  195. data/maps/risorgimento.map +0 -0
  196. data/maps/sherbet.map +0 -0
  197. data/maps/simple.map +0 -0
  198. data/maps/slouch.map +0 -0
  199. data/maps/space_st.ifm +0 -0
  200. data/maps/splashdown.map +0 -0
  201. data/maps/spring.map +0 -0
  202. data/maps/squarecircle.map +0 -0
  203. data/maps/stationfall.ifm +0 -0
  204. data/maps/theatre.ifm +0 -0
  205. data/maps/toonesia.ifm +0 -0
  206. data/maps/tortoise.ifm +0 -0
  207. data/maps/trinity.map +0 -0
  208. data/maps/vespers.map +0 -0
  209. data/maps/vgame.ifm +0 -0
  210. data/maps/wasp.map +0 -0
  211. data/maps/weather.ifm +0 -0
  212. data/maps/windhall.ifm +0 -0
  213. data/maps/worlds.map +0 -0
  214. data/maps/xtcontest.map +0 -0
  215. data/maps/zdungeon.map +0 -0
  216. data/maps/zebulon.ifm +0 -0
  217. data/maps/zerosum.map +0 -0
  218. metadata +226 -183
@@ -1,445 +1,445 @@
1
-
2
- require "IFMapper/Map"
3
-
4
- class FXMap; end
5
-
6
- #
7
- # Class that allows importing a GUE map file.
8
- #
9
- class GUEReader
10
-
11
- class ParseError < StandardError; end
12
- class MapError < StandardError; end
13
-
14
- # This is the GUEmap magic number/ID at the beginning of the file.
15
- GUE_MAGIC = "\307U\305m\341p"
16
-
17
- DIRS = {
18
- 0 => 0, # n
19
- 1 => 4, # s
20
- 2 => 2, # e
21
- 3 => 6, # w
22
- 4 => 1, # ne
23
- 5 => 7, # nw
24
- 6 => 3, # se
25
- 7 => 5, # sw
26
-
27
- # GUE Map also supports connections to the sides of centers
28
- #
29
- # -*--*-
30
- # | |
31
- # -*--*-
32
- #
33
- # We translate these as corner connections.
34
- #
35
- 8 => [0, 1], # ----*-
36
- 9 => [0, 7],
37
- 10 => [4, 3], # ----*-
38
- 11 => [4, 5],
39
-
40
- # DOT directions
41
- # 12 => 4,
42
- }
43
-
44
-
45
- class Complex
46
- attr_accessor :roomA, :dirA, :roomB, :dirB
47
- end
48
-
49
-
50
- attr_reader :map
51
-
52
- @@debug = nil
53
-
54
- def debug(x)
55
- if @@debug.to_i > 0
56
- $stderr.puts x
57
- end
58
- end
59
-
60
- #
61
- # Read GUEMap header from file stream
62
- #
63
- def header
64
- magic = @f.read(6)
65
- if magic != GUE_MAGIC
66
- raise ParseError, "Not a GUEMap"
67
- end
68
- @f.read(4)
69
- version = @f.read(2).unpack('s')[0]
70
- debug "VERSION: #{version}"
71
- case version
72
- when 4
73
- crap = @f.read(2)
74
- crap = @f.read(1)[0]
75
- if crap == 32
76
- len = @f.read(1)[0]
77
- @map.name = @f.read(len)
78
- crap = @f.read(1)[0]
79
- end
80
- if crap == 40
81
- len = @f.read(1)[0]
82
- if len == 255
83
- len = @f.read(2).unpack('s')[0]
84
- end
85
- @f.read(len)
86
- crap = @f.read(1)[0]
87
- end
88
- hdr = @f.read(15)
89
- when 3,2
90
- crap = @f.read(2)
91
- crap = @f.read(1)[0]
92
- if crap == 32
93
- len = @f.read(1)[0]
94
- @map.name = @f.read(len)
95
- crap = @f.read(1)[0]
96
- end
97
- if crap == 40
98
- len = @f.read(1)[0]
99
- if len == 255
100
- len = @f.read(2).unpack('s')[0]
101
- end
102
- @f.read(len)
103
- crap = @f.read(1)[0]
104
- end
105
- hdr = @f.read(8)
106
- else
107
- raise ParseError, "Unknown GUEMap version #{version}"
108
- end
109
- end
110
-
111
- #
112
- # Read a connection from file stream
113
- #
114
- def read_connection
115
- type = Connection::FREE
116
- dir = Connection::BOTH
117
- dA = @f.read(1)[0]
118
- a = @f.read(1)[0]
119
- stub = false
120
-
121
- opt = @f.read(1)[0]
122
- exitAtext = exitBtext = 0
123
-
124
- case opt
125
- when 26
126
- #normal connection
127
- when 34
128
- # up/down/in/out connection
129
- exitAtext = @f.read(1)[0]
130
- if exitAtext & 8 != 0
131
- exitAtext -= 8
132
- type = Connection::SPECIAL
133
- end
134
- if exitAtext & 16 != 0
135
- # no exit connection
136
- stub = true
137
- exitAtext -= 16
138
- b = a
139
- dB = dA
140
- end
141
- if exitAtext & 32 != 0
142
- # stub connection
143
- stub = true
144
- exitAtext -= 32
145
- end
146
- if exitAtext & 64 != 0
147
- exitAtext -= 64
148
- dir = Connection::AtoB
149
- end
150
- exitBtext = @f.read(1)[0]
151
- data = @f.read(1)[0]
152
- else
153
- raise ParseError, "option: #{opt} unknown"
154
- end
155
-
156
- unless stub
157
- dB = @f.read(1)[0]
158
- b = @f.read(1)[0]
159
- opt = @f.read(1)[0]
160
- end
161
-
162
- data = @f.read(1)[0]
163
- data = @f.read(1)[0] unless @f.eof?
164
-
165
- section = @map.sections[@map.section]
166
- roomA = section.rooms[a]
167
- roomB = section.rooms[b] if b
168
-
169
-
170
- debug "Index : #{a}->#{b}"
171
- debug "dA: #{dA} dB: #{dB}"
172
- if roomA.name == '*'
173
- if roomB.x != roomA.x or roomB.y != roomA.y
174
- dirA = roomA.exit_to(roomB)
175
- else
176
- dirA = 0
177
- end
178
- else
179
- dirA = DIRS[dA]
180
- if dirA.kind_of?(Array)
181
- dirA.each { |d|
182
- next if roomA[d]
183
- dirA = d
184
- break
185
- }
186
- if dirA.kind_of?(Array)
187
- dirA = dirA[0]
188
- end
189
- end
190
- raise "Unknown direction #{dA}" unless dirA
191
- end
192
-
193
- if b
194
- if roomB.name == '*'
195
- dirB = (dirA + 4) % 8
196
- else
197
- dirB = DIRS[dB]
198
- if dirB.kind_of?(Array)
199
- dirB.each { |d|
200
- next if roomB[d]
201
- dirB = d
202
- break
203
- }
204
- if dirB.kind_of?(Array)
205
- dirB = dirB[0]
206
- end
207
- end
208
- raise "Unknown direction #{dB}" unless dirB
209
- end
210
- end
211
-
212
-
213
- if roomA[dirA]
214
- dirA = roomA.exits.index(nil)
215
- end
216
-
217
- if roomB
218
- if roomB[dirB]
219
- dirB = roomB.exits.rindex(nil)
220
- end
221
- end
222
-
223
-
224
- debug "Connect: #{roomA} ->#{roomB} "
225
- debug "dirA: #{dirA} dirB: #{dirB}"
226
- debug "exitA: #{exitAtext} exitB: #{exitBtext}"
227
-
228
- begin
229
- c = map.new_connection( roomA, dirA, roomB, dirB )
230
-
231
- c.exitAtext = exitAtext
232
- c.exitBtext = exitBtext
233
- c.dir = dir
234
- c.type = type
235
-
236
- debug c
237
- rescue Section::ConnectionError
238
- end
239
-
240
- end
241
-
242
-
243
- #
244
- # Read a room from file stream
245
- #
246
- def read_room
247
- x = @f.read(1)[0]
248
- data = @f.read(1)
249
- y = @f.read(1)[0]
250
- data = @f.read(1)[0]
251
-
252
- type = @f.read(1)[0]
253
-
254
- case type
255
- when 41
256
- r = @map.new_room(x, y)
257
- r.name = "*"
258
- data = @f.read(4)
259
- if data[0] == 0
260
- r.name = ''
261
- end
262
- return
263
- when 0
264
- r = @map.new_room(x, y)
265
- r.name = ''
266
- @f.read(2)
267
- return
268
- end
269
-
270
- len = @f.read(1)[0]
271
- name = ''
272
- comment = ''
273
-
274
- name = @f.read(len)
275
- test = @f.read(1)[0]
276
-
277
- case test
278
- when 41
279
- @f.read(4)
280
- when 0
281
- data = @f.read(2)
282
- else
283
- len = @f.read(1)[0]
284
- if len == 255
285
- len = @f.read(2).unpack('s')[0]
286
- end
287
- comment = @f.read(len)
288
- data = @f.read(3)
289
- end
290
- debug "Room: #{name.inspect} pos: #{x}, #{y}"
291
- debug "Comment: #{comment.inspect}"
292
-
293
- # r = @map.new_room(x, y)
294
- r = @map.new_room(x, y)
295
- name.gsub!(/[\r\n]+/, ' ')
296
- comment.gsub!(/\r/, '')
297
-
298
- r.name = name
299
- r.tasks = comment
300
- end
301
-
302
- #
303
- # Main parsing loop.
304
- #
305
- def parse
306
- header
307
- while not @f.eof?
308
- type = @f.read(1)[0]
309
- data = @f.read(1)[0]
310
-
311
- debug "type: #{type}"
312
- debug "data: #{data}"
313
-
314
- case type
315
- when 2
316
- read_room
317
- when 3
318
- read_connection
319
- when 4
320
- break
321
- else
322
- raise "Unknown type: #{type}"
323
- end
324
- end
325
- end
326
-
327
- def remove_dots
328
- @map.sections.each do |sect|
329
- sect.connections.each do |c|
330
- a, b = c.room
331
- next unless b
332
- next if a.name == '*' or b.name != '*'
333
- # OK. We have a ROOM->* connection. Follow it to find other room.
334
- # And turn it into a complex connection.
335
- dirA = a.exits.index(c)
336
- dirB = b.exits.rindex(c)
337
- origB = dirB
338
- dir = Connection::BOTH
339
- dirB = nil
340
- cc = c
341
- while b.name == '*'
342
- found = false
343
- b.exits.each { |e|
344
- next if not e or e == cc
345
- found = true
346
- idx = e.index(b) ^ 1
347
- b = e.room[idx]
348
- dirB = b.exits.index(e)
349
- dir = e.dir
350
- cc = e
351
- break
352
- }
353
- if not found
354
- debug "not found complement for #{cc}"
355
- break
356
- end
357
- end
358
-
359
- next if b.name == '*'
360
-
361
- # remove the other connection
362
- sect.delete_connection(cc)
363
-
364
- c.roomB[origB] = nil
365
-
366
- # Make connection a complex connection and remove old
367
- # connection in b room
368
- c.roomB = b
369
- c.dir = dir
370
- b[dirB] = c
371
- end
372
- end
373
-
374
-
375
- # Now, remove all DOT rooms and their connections
376
- @map.sections.each { |sect|
377
- del = sect.rooms.find_all { |r| r.name == '*' }
378
- del.each { |r|
379
- sect.delete_room(r)
380
- }
381
- }
382
- end
383
-
384
- def reposition
385
- @map.sections.each do |sect|
386
- minXY, = sect.min_max_rooms
387
- sect.rooms.each do |r|
388
- r.x -= minXY[0]
389
- r.y -= minXY[1]
390
- r.x /= 4.0
391
- r.y /= 4.0
392
- end
393
- end
394
-
395
- @map.sections.each do |sect|
396
- sect.rooms.each_with_index do |r, idx|
397
- x = r.x
398
- y = r.y
399
- xf = x.floor
400
- yf = y.floor
401
- if x != xf or y != yf
402
- sect.rooms.each do |r2|
403
- next if r == r2
404
- if xf == r2.x.floor and yf == r2.y.floor
405
- dx = (x - xf).ceil
406
- dy = (y - yf).ceil
407
- sect.shift(x, y, dx, dy)
408
- break
409
- end
410
- end
411
- end
412
- r.x = r.x.floor.to_i
413
- r.y = r.y.floor.to_i
414
- end
415
- end
416
- end
417
-
418
-
419
- def initialize(file, map = Map.new('GUE Imported Map'))
420
- @map = map
421
- @complex = []
422
-
423
- @f = File.open(file, 'rb')
424
- parse
425
-
426
- reposition
427
- remove_dots
428
-
429
- @map.fit
430
- @map.section = 0
431
- if @map.kind_of?(FXMap)
432
- @map.filename = file.sub(/\.gmp$/i, '.map')
433
- @map.navigation = true
434
- @map.window.show
435
- end
436
- end
437
- end
438
-
439
-
440
- if $0 == __FILE__
441
- puts "Opening file '#{ARGV[0]}'"
442
- require "IFMapper/Map"
443
-
444
- GUEReader.new(ARGV[0])
445
- end
1
+
2
+ require "IFMapper/Map"
3
+
4
+ class FXMap; end
5
+
6
+ #
7
+ # Class that allows importing a GUE map file.
8
+ #
9
+ class GUEReader
10
+
11
+ class ParseError < StandardError; end
12
+ class MapError < StandardError; end
13
+
14
+ # This is the GUEmap magic number/ID at the beginning of the file.
15
+ GUE_MAGIC = "\307U\305m\341p"
16
+
17
+ DIRS = {
18
+ 0 => 0, # n
19
+ 1 => 4, # s
20
+ 2 => 2, # e
21
+ 3 => 6, # w
22
+ 4 => 1, # ne
23
+ 5 => 7, # nw
24
+ 6 => 3, # se
25
+ 7 => 5, # sw
26
+
27
+ # GUE Map also supports connections to the sides of centers
28
+ #
29
+ # -*--*-
30
+ # | |
31
+ # -*--*-
32
+ #
33
+ # We translate these as corner connections.
34
+ #
35
+ 8 => [0, 1], # ----*-
36
+ 9 => [0, 7],
37
+ 10 => [4, 3], # ----*-
38
+ 11 => [4, 5],
39
+
40
+ # DOT directions
41
+ # 12 => 4,
42
+ }
43
+
44
+
45
+ class Complex
46
+ attr_accessor :roomA, :dirA, :roomB, :dirB
47
+ end
48
+
49
+
50
+ attr_reader :map
51
+
52
+ @@debug = nil
53
+
54
+ def debug(x)
55
+ if @@debug.to_i > 0
56
+ $stderr.puts x
57
+ end
58
+ end
59
+
60
+ #
61
+ # Read GUEMap header from file stream
62
+ #
63
+ def header
64
+ magic = @f.read(6)
65
+ if magic != GUE_MAGIC
66
+ raise ParseError, "Not a GUEMap"
67
+ end
68
+ @f.read(4)
69
+ version = @f.read(2).unpack('s')[0]
70
+ debug "VERSION: #{version}"
71
+ case version
72
+ when 4
73
+ crap = @f.read(2)
74
+ crap = @f.read(1)[0]
75
+ if crap == 32
76
+ len = @f.read(1)[0]
77
+ @map.name = @f.read(len)
78
+ crap = @f.read(1)[0]
79
+ end
80
+ if crap == 40
81
+ len = @f.read(1)[0]
82
+ if len == 255
83
+ len = @f.read(2).unpack('s')[0]
84
+ end
85
+ @f.read(len)
86
+ crap = @f.read(1)[0]
87
+ end
88
+ hdr = @f.read(15)
89
+ when 3,2
90
+ crap = @f.read(2)
91
+ crap = @f.read(1)[0]
92
+ if crap == 32
93
+ len = @f.read(1)[0]
94
+ @map.name = @f.read(len)
95
+ crap = @f.read(1)[0]
96
+ end
97
+ if crap == 40
98
+ len = @f.read(1)[0]
99
+ if len == 255
100
+ len = @f.read(2).unpack('s')[0]
101
+ end
102
+ @f.read(len)
103
+ crap = @f.read(1)[0]
104
+ end
105
+ hdr = @f.read(8)
106
+ else
107
+ raise ParseError, "Unknown GUEMap version #{version}"
108
+ end
109
+ end
110
+
111
+ #
112
+ # Read a connection from file stream
113
+ #
114
+ def read_connection
115
+ type = Connection::FREE
116
+ dir = Connection::BOTH
117
+ dA = @f.read(1)[0]
118
+ a = @f.read(1)[0]
119
+ stub = false
120
+
121
+ opt = @f.read(1)[0]
122
+ exitAtext = exitBtext = 0
123
+
124
+ case opt
125
+ when 26
126
+ #normal connection
127
+ when 34
128
+ # up/down/in/out connection
129
+ exitAtext = @f.read(1)[0]
130
+ if exitAtext & 8 != 0
131
+ exitAtext -= 8
132
+ type = Connection::SPECIAL
133
+ end
134
+ if exitAtext & 16 != 0
135
+ # no exit connection
136
+ stub = true
137
+ exitAtext -= 16
138
+ b = a
139
+ dB = dA
140
+ end
141
+ if exitAtext & 32 != 0
142
+ # stub connection
143
+ stub = true
144
+ exitAtext -= 32
145
+ end
146
+ if exitAtext & 64 != 0
147
+ exitAtext -= 64
148
+ dir = Connection::AtoB
149
+ end
150
+ exitBtext = @f.read(1)[0]
151
+ data = @f.read(1)[0]
152
+ else
153
+ raise ParseError, "option: #{opt} unknown"
154
+ end
155
+
156
+ unless stub
157
+ dB = @f.read(1)[0]
158
+ b = @f.read(1)[0]
159
+ opt = @f.read(1)[0]
160
+ end
161
+
162
+ data = @f.read(1)[0]
163
+ data = @f.read(1)[0] unless @f.eof?
164
+
165
+ section = @map.sections[@map.section]
166
+ roomA = section.rooms[a]
167
+ roomB = section.rooms[b] if b
168
+
169
+
170
+ debug "Index : #{a}->#{b}"
171
+ debug "dA: #{dA} dB: #{dB}"
172
+ if roomA.name == '*'
173
+ if roomB.x != roomA.x or roomB.y != roomA.y
174
+ dirA = roomA.exit_to(roomB)
175
+ else
176
+ dirA = 0
177
+ end
178
+ else
179
+ dirA = DIRS[dA]
180
+ if dirA.kind_of?(Array)
181
+ dirA.each { |d|
182
+ next if roomA[d]
183
+ dirA = d
184
+ break
185
+ }
186
+ if dirA.kind_of?(Array)
187
+ dirA = dirA[0]
188
+ end
189
+ end
190
+ raise "Unknown direction #{dA}" unless dirA
191
+ end
192
+
193
+ if b
194
+ if roomB.name == '*'
195
+ dirB = (dirA + 4) % 8
196
+ else
197
+ dirB = DIRS[dB]
198
+ if dirB.kind_of?(Array)
199
+ dirB.each { |d|
200
+ next if roomB[d]
201
+ dirB = d
202
+ break
203
+ }
204
+ if dirB.kind_of?(Array)
205
+ dirB = dirB[0]
206
+ end
207
+ end
208
+ raise "Unknown direction #{dB}" unless dirB
209
+ end
210
+ end
211
+
212
+
213
+ if roomA[dirA]
214
+ dirA = roomA.exits.index(nil)
215
+ end
216
+
217
+ if roomB
218
+ if roomB[dirB]
219
+ dirB = roomB.exits.rindex(nil)
220
+ end
221
+ end
222
+
223
+
224
+ debug "Connect: #{roomA} ->#{roomB} "
225
+ debug "dirA: #{dirA} dirB: #{dirB}"
226
+ debug "exitA: #{exitAtext} exitB: #{exitBtext}"
227
+
228
+ begin
229
+ c = map.new_connection( roomA, dirA, roomB, dirB )
230
+
231
+ c.exitAtext = exitAtext
232
+ c.exitBtext = exitBtext
233
+ c.dir = dir
234
+ c.type = type
235
+
236
+ debug c
237
+ rescue Section::ConnectionError
238
+ end
239
+
240
+ end
241
+
242
+
243
+ #
244
+ # Read a room from file stream
245
+ #
246
+ def read_room
247
+ x = @f.read(1)[0]
248
+ data = @f.read(1)
249
+ y = @f.read(1)[0]
250
+ data = @f.read(1)[0]
251
+
252
+ type = @f.read(1)[0]
253
+
254
+ case type
255
+ when 41
256
+ r = @map.new_room(x, y)
257
+ r.name = "*"
258
+ data = @f.read(4)
259
+ if data[0] == 0
260
+ r.name = ''
261
+ end
262
+ return
263
+ when 0
264
+ r = @map.new_room(x, y)
265
+ r.name = ''
266
+ @f.read(2)
267
+ return
268
+ end
269
+
270
+ len = @f.read(1)[0]
271
+ name = ''
272
+ comment = ''
273
+
274
+ name = @f.read(len)
275
+ test = @f.read(1)[0]
276
+
277
+ case test
278
+ when 41
279
+ @f.read(4)
280
+ when 0
281
+ data = @f.read(2)
282
+ else
283
+ len = @f.read(1)[0]
284
+ if len == 255
285
+ len = @f.read(2).unpack('s')[0]
286
+ end
287
+ comment = @f.read(len)
288
+ data = @f.read(3)
289
+ end
290
+ debug "Room: #{name.inspect} pos: #{x}, #{y}"
291
+ debug "Comment: #{comment.inspect}"
292
+
293
+ # r = @map.new_room(x, y)
294
+ r = @map.new_room(x, y)
295
+ name.gsub!(/[\r\n]+/, ' ')
296
+ comment.gsub!(/\r/, '')
297
+
298
+ r.name = name
299
+ r.tasks = comment
300
+ end
301
+
302
+ #
303
+ # Main parsing loop.
304
+ #
305
+ def parse
306
+ header
307
+ while not @f.eof?
308
+ type = @f.read(1)[0]
309
+ data = @f.read(1)[0]
310
+
311
+ debug "type: #{type}"
312
+ debug "data: #{data}"
313
+
314
+ case type
315
+ when 2
316
+ read_room
317
+ when 3
318
+ read_connection
319
+ when 4
320
+ break
321
+ else
322
+ raise "Unknown type: #{type}"
323
+ end
324
+ end
325
+ end
326
+
327
+ def remove_dots
328
+ @map.sections.each do |sect|
329
+ sect.connections.each do |c|
330
+ a, b = c.room
331
+ next unless b
332
+ next if a.name == '*' or b.name != '*'
333
+ # OK. We have a ROOM->* connection. Follow it to find other room.
334
+ # And turn it into a complex connection.
335
+ dirA = a.exits.index(c)
336
+ dirB = b.exits.rindex(c)
337
+ origB = dirB
338
+ dir = Connection::BOTH
339
+ dirB = nil
340
+ cc = c
341
+ while b.name == '*'
342
+ found = false
343
+ b.exits.each { |e|
344
+ next if not e or e == cc
345
+ found = true
346
+ idx = e.index(b) ^ 1
347
+ b = e.room[idx]
348
+ dirB = b.exits.index(e)
349
+ dir = e.dir
350
+ cc = e
351
+ break
352
+ }
353
+ if not found
354
+ debug "not found complement for #{cc}"
355
+ break
356
+ end
357
+ end
358
+
359
+ next if b.name == '*'
360
+
361
+ # remove the other connection
362
+ sect.delete_connection(cc)
363
+
364
+ c.roomB[origB] = nil
365
+
366
+ # Make connection a complex connection and remove old
367
+ # connection in b room
368
+ c.roomB = b
369
+ c.dir = dir
370
+ b[dirB] = c
371
+ end
372
+ end
373
+
374
+
375
+ # Now, remove all DOT rooms and their connections
376
+ @map.sections.each { |sect|
377
+ del = sect.rooms.find_all { |r| r.name == '*' }
378
+ del.each { |r|
379
+ sect.delete_room(r)
380
+ }
381
+ }
382
+ end
383
+
384
+ def reposition
385
+ @map.sections.each do |sect|
386
+ minXY, = sect.min_max_rooms
387
+ sect.rooms.each do |r|
388
+ r.x -= minXY[0]
389
+ r.y -= minXY[1]
390
+ r.x /= 4.0
391
+ r.y /= 4.0
392
+ end
393
+ end
394
+
395
+ @map.sections.each do |sect|
396
+ sect.rooms.each_with_index do |r, idx|
397
+ x = r.x
398
+ y = r.y
399
+ xf = x.floor
400
+ yf = y.floor
401
+ if x != xf or y != yf
402
+ sect.rooms.each do |r2|
403
+ next if r == r2
404
+ if xf == r2.x.floor and yf == r2.y.floor
405
+ dx = (x - xf).ceil
406
+ dy = (y - yf).ceil
407
+ sect.shift(x, y, dx, dy)
408
+ break
409
+ end
410
+ end
411
+ end
412
+ r.x = r.x.floor.to_i
413
+ r.y = r.y.floor.to_i
414
+ end
415
+ end
416
+ end
417
+
418
+
419
+ def initialize(file, map = Map.new('GUE Imported Map'))
420
+ @map = map
421
+ @complex = []
422
+
423
+ @f = File.open(file, 'rb')
424
+ parse
425
+
426
+ reposition
427
+ remove_dots
428
+
429
+ @map.fit
430
+ @map.section = 0
431
+ if @map.kind_of?(FXMap)
432
+ @map.filename = file.sub(/\.gmp$/i, '.map')
433
+ @map.navigation = true
434
+ @map.window.show
435
+ end
436
+ end
437
+ end
438
+
439
+
440
+ if $0 == __FILE__
441
+ puts "Opening file '#{ARGV[0]}'"
442
+ require "IFMapper/Map"
443
+
444
+ GUEReader.new(ARGV[0])
445
+ end