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,364 +1,364 @@
1
-
2
- require 'IFMapper/FXSpline'
3
- require 'IFMapper/Connection'
4
- require 'IFMapper/FXConnectionDialogBox'
5
-
6
- ######################################################
7
- #
8
- # WW
9
- # +---------------------+
10
- # | W |
11
- # | +-------------+ |
12
- # HH | | |WS2|
13
- # | H | |---|
14
- # | +-------------+ |
15
- # | |HS2 |
16
- # +---------------------+
17
- #
18
- #####################################################
19
-
20
- W = 120
21
- H = 75
22
- WS = 40
23
- HS = 40
24
- WW = W+WS
25
- HH = H+HS
26
-
27
- WS_2 = WS / 2
28
- HS_2 = HS / 2
29
-
30
- WIDX = 24
31
- HIDX = 18
32
-
33
-
34
- class FXConnection < Connection
35
- attr_accessor :selected
36
- attr_accessor :failed
37
- attr_accessor :pts, :gpts
38
-
39
- @@win = nil
40
-
41
- def self.no_maps
42
- @@win.hide if @@win
43
- end
44
-
45
- def initialize( roomA, roomB, dir = Connection::BOTH,
46
- type = Connection::FREE )
47
- super( roomA, roomB, dir, type )
48
- @selected = @failed = false
49
- @pts = @gpts = []
50
- end
51
-
52
- def marshal_load(vars)
53
- @pts = @gpts = []
54
- @selected = vars.shift
55
- super(vars)
56
- end
57
-
58
- def marshal_dump
59
- [ @selected ] + super
60
- end
61
-
62
- def flip
63
- super
64
- pts.reverse!
65
- gpts.reverse!
66
- @@win.copy_from(self) if @@win
67
- end
68
-
69
- #
70
- # Change selection state of connection. If Connection Properties
71
- # window is open, copy the connection data to it.
72
- #
73
- def selected=(value)
74
- @@win.copy_from(self) if value and @@win and @@win.shown?
75
- @selected = value
76
- end
77
-
78
- #
79
- # Change direction of connection
80
- #
81
- def toggle_direction
82
- # If a self-loop, we cannot change dir
83
- return if @room[0] == @room[1] and
84
- @room[0].exits.index(self) == @room[0].exits.rindex(self)
85
-
86
- @dir ^= 1
87
- @@win.copy_from(self) if @@win
88
- end
89
-
90
- #
91
- # Is this a complex path. Check if connection is
92
- # contiguous
93
- #
94
- def complex?()
95
- return false if not @room[1]
96
- return true if @room[1] == @room[0]
97
- return true unless @room[0].next_to?(@room[1])
98
-
99
- # Even if rooms are next to each other, we need to
100
- # verify that following the exits does indeed take us to next room.
101
- exitA = @room[0].exits.index(self)
102
- dir = Room::DIR_TO_VECTOR[exitA]
103
-
104
- if @room[0].x + dir[0] == @room[1].x and
105
- @room[0].y + dir[1] == @room[1].y
106
- exitB = @room[1].exits.rindex(self)
107
- dir = Room::DIR_TO_VECTOR[exitB]
108
- if @room[1].x + dir[0] == @room[0].x and
109
- @room[1].y + dir[1] == @room[0].y
110
- return false
111
- else
112
- return true
113
- end
114
- else
115
- return true
116
- end
117
- end
118
-
119
- #
120
- # Main draw function
121
- #
122
- def draw(dc, zoom, opt)
123
- if @selected
124
- dc.foreground = 'yellow'
125
- elsif @failed
126
- dc.foreground = 'red'
127
- else
128
- dc.foreground = opt['Arrow Color']
129
- end
130
-
131
- draw_exit_text(dc, zoom)
132
- if @type == SPECIAL
133
- dc.lineStyle = LINE_ONOFF_DASH
134
- else
135
- dc.lineStyle = LINE_SOLID
136
- end
137
- if pts.size > 0
138
- draw_complex(dc, zoom, opt)
139
- else
140
- draw_simple(dc, zoom)
141
- end
142
- end
143
-
144
-
145
- def update_properties(map)
146
- return if not @@win or not @@win.shown?
147
- @@win.map = map
148
- @@win.copy_from(self)
149
- end
150
-
151
- def properties(map, event = nil)
152
- if not @@win
153
- @@win = FXConnectionDialogBox.new(map, self, event)
154
- end
155
- @@win.show
156
- update_properties(map)
157
- end
158
-
159
- protected
160
-
161
- RAD_45 = 45 * Math::PI / 180
162
- SIN_45 = Math.sin(RAD_45)
163
- COS_45 = Math.cos(RAD_45)
164
-
165
- def _arrow_info( x1, y1, x2, y2, zoom = 1.0 )
166
- pt1 = []
167
- dir = 0
168
- dir = @room[1].exits.rindex(self)
169
- pt1 = [ x2, y2 ]
170
- x, y = Room::DIR_TO_VECTOR[dir]
171
- if @room[0] == @room[1]
172
- size = 15.0
173
- else
174
- size = 20.0
175
- end
176
- arrow_len = size / Math.sqrt(x * x + y * y)
177
- x *= arrow_len * zoom
178
- y *= arrow_len * -zoom
179
-
180
- d = [
181
- x * COS_45 + y * SIN_45,
182
- x * SIN_45 - y * COS_45
183
- ]
184
- return pt1, d
185
- end
186
-
187
-
188
- #
189
- # Draw a complex connection as a line path
190
- #
191
- def draw_complex_as_lines(dc, zoom)
192
- p = []
193
- @pts.each { |pt|
194
- p << FXPoint.new( (pt[0] * zoom).to_i, (pt[1] * zoom).to_i )
195
- }
196
- dc.drawLines( p )
197
- return p
198
- end
199
-
200
- #
201
- # Draw a complex connection as a bspline path
202
- #
203
- def draw_complex_as_bspline(dc, zoom)
204
- p = []
205
- p << [ @pts[0][0] * zoom, @pts[0][1] * zoom ]
206
- p << p[0]
207
- p << p[0]
208
- @pts.each { |pt|
209
- p << [ pt[0] * zoom, pt[1] * zoom ]
210
- }
211
- p << p[-1]
212
- p << p[-1]
213
- p << p[-1]
214
- return dc.drawBSpline( p )
215
- end
216
-
217
- #
218
- # Draw a door
219
- #
220
- def draw_door(dc, zoom, x1, y1, x2, y2)
221
- v = [ (x2-x1), (y2-y1) ]
222
- t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
223
- v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
224
- m = [ (x2+x1)/2, (y2+y1)/2 ]
225
- x1, y1 = [m[0] + v[1], m[1] - v[0]]
226
- x2, y2 = [m[0] - v[1], m[1] + v[0]]
227
- if @type == LOCKED_DOOR
228
- # Locked door
229
- dc.drawLine(x1, y1, x2, y2)
230
- else
231
- # open door
232
- v = [ v[0] / 3, v[1] / 3]
233
- x1, y1 = x1.to_i, y1.to_i
234
- x2, y2 = x2.to_i, y2.to_i
235
- pts = []
236
- pts << FXPoint.new(x1 - v[0], y1 - v[1])
237
- pts << FXPoint.new(x1 + v[0], y1 + v[1])
238
- pts << FXPoint.new(x2 + v[0], y2 + v[1])
239
- pts << FXPoint.new(x2 - v[0], y2 - v[1])
240
- pts << pts[0]
241
- width = dc.lineWidth
242
- dc.lineWidth = 0
243
- dc.drawLines(pts)
244
- dc.lineWidth = width
245
- end
246
- end
247
-
248
- #
249
- # Draw a complex connection
250
- #
251
- def draw_complex(dc, zoom, opt)
252
- if opt['Paths as Curves']
253
- if @room[0] == @room[1]
254
- dirA, dirB = dirs
255
- if dirA == dirB
256
- p = draw_complex_as_lines(dc, zoom)
257
- else
258
- p = draw_complex_as_bspline(dc, zoom)
259
- end
260
- else
261
- p = draw_complex_as_bspline(dc, zoom)
262
- end
263
- else
264
- p = draw_complex_as_lines(dc, zoom)
265
- end
266
-
267
- x1, y1 = [p[0].x, p[0].y]
268
- x2, y2 = [p[-1].x, p[-1].y]
269
- draw_arrow(dc, zoom, x1, y1, x2, y2)
270
-
271
- if @type == LOCKED_DOOR or @type == CLOSED_DOOR
272
- t = p.size / 2
273
- x1, y1 = [ p[t].x, p[t].y ]
274
- x2, y2 = [ p[t-2].x, p[t-2].y ]
275
- draw_door(dc, zoom, x1, y1, x2, y2)
276
- end
277
- end
278
-
279
- #
280
- # Draw a simple connection. Simple connections are straight
281
- # line connections or 'stub' connections.
282
- #
283
- def draw_simple(dc, zoom)
284
- dir = @room[0].exits.index(self)
285
- x1, y1 = @room[0].corner(self, zoom, dir)
286
- if @room[1]
287
- x2, y2 = @room[1].corner(self, zoom)
288
- dc.drawLine( x1, y1, x2, y2 )
289
- draw_arrow(dc, zoom, x1, y1, x2, y2)
290
- if @type == LOCKED_DOOR or @type == CLOSED_DOOR
291
- draw_door(dc, zoom, x1, y1, x2, y2)
292
- end
293
- else
294
- # Complex connection in progress or "stub" exit
295
- v = FXRoom::DIR_TO_VECTOR[dir]
296
- x2, y2 = [ x1 + v[0] * WS * zoom * 0.4, y1 + v[1] * HS * zoom * 0.4 ]
297
- dc.drawLine( x1, y1, x2, y2 )
298
- end
299
- end
300
-
301
-
302
- #
303
- # Draw an arrow at one end of the path
304
- #
305
- def draw_arrow( dc, zoom, x1, y1, x2, y2 )
306
- return if @dir == BOTH
307
- pt1, d = _arrow_info( x1, y1, x2, y2, zoom )
308
-
309
- p = []
310
- p << FXPoint.new( pt1[0].to_i, pt1[1].to_i )
311
- pt2 = [ pt1[0] + d[0], pt1[1] + d[1] ]
312
- p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
313
- pt2 = [ pt1[0] + d[1], pt1[1] - d[0] ]
314
- p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
315
-
316
- dc.fillPolygon(p)
317
- end
318
-
319
- #
320
- # Draw the connection text next to the arrow ('I', 'O', etc)
321
- #
322
- def draw_text(dc, zoom, x, y, dir, text, arrow)
323
- if dir == 7 or dir < 6 and dir != 1
324
- if arrow and (dir == 0 or dir == 4)
325
- x += 10 * zoom
326
- end
327
- x += 5 * zoom
328
- elsif dir == 6 or dir == 1
329
- x -= 15 * zoom
330
- end
331
-
332
- if dir > 5 or dir < 4
333
- if arrow and (dir == 6 or dir == 2)
334
- y -= 10 * zoom
335
- end
336
- y -= 5 * zoom
337
- elsif dir == 4 or dir == 5
338
- y += 15 * zoom
339
- end
340
-
341
- dc.drawText(x, y, text)
342
- end
343
-
344
- #
345
- # Draw any exit text if available (exit text is 'U', 'D', 'I', 'O', etc)
346
- #
347
- def draw_exit_text(dc, zoom)
348
- return if zoom < 0.5
349
- if @exitText[0] != 0
350
- dir = @room[0].exits.index(self)
351
- x, y = @room[0].corner(self, zoom, dir)
352
- draw_text( dc, zoom, x, y, dir,
353
- DRAW_EXIT_TEXT[@exitText[0]], nil )
354
- end
355
- if @exitText[1] != 0
356
- dir = @room[1].exits.rindex(self)
357
- x, y = @room[1].corner(self, zoom, dir)
358
- draw_text( dc, zoom, x, y, dir,
359
- DRAW_EXIT_TEXT[@exitText[1]], @dir == AtoB)
360
- end
361
- end
362
-
363
- end
364
-
1
+
2
+ require 'IFMapper/FXSpline'
3
+ require 'IFMapper/Connection'
4
+ require 'IFMapper/FXConnectionDialogBox'
5
+
6
+ ######################################################
7
+ #
8
+ # WW
9
+ # +---------------------+
10
+ # | W |
11
+ # | +-------------+ |
12
+ # HH | | |WS2|
13
+ # | H | |---|
14
+ # | +-------------+ |
15
+ # | |HS2 |
16
+ # +---------------------+
17
+ #
18
+ #####################################################
19
+
20
+ W = 120
21
+ H = 75
22
+ WS = 40
23
+ HS = 40
24
+ WW = W+WS
25
+ HH = H+HS
26
+
27
+ WS_2 = WS / 2
28
+ HS_2 = HS / 2
29
+
30
+ WIDX = 24
31
+ HIDX = 18
32
+
33
+
34
+ class FXConnection < Connection
35
+ attr_reader :selected
36
+ attr_accessor :failed
37
+ attr_accessor :pts, :gpts
38
+
39
+ @@win = nil
40
+
41
+ def self.no_maps
42
+ @@win.hide if @@win
43
+ end
44
+
45
+ def initialize( roomA, roomB, dir = Connection::BOTH,
46
+ type = Connection::FREE )
47
+ super( roomA, roomB, dir, type )
48
+ @selected = @failed = false
49
+ @pts = @gpts = []
50
+ end
51
+
52
+ def marshal_load(vars)
53
+ @pts = @gpts = []
54
+ @selected = vars.shift
55
+ super(vars)
56
+ end
57
+
58
+ def marshal_dump
59
+ [ @selected ] + super
60
+ end
61
+
62
+ def flip
63
+ super
64
+ pts.reverse!
65
+ gpts.reverse!
66
+ @@win.copy_from(self) if @@win
67
+ end
68
+
69
+ #
70
+ # Change selection state of connection. If Connection Properties
71
+ # window is open, copy the connection data to it.
72
+ #
73
+ def selected=(value)
74
+ @@win.copy_from(self) if value and @@win and @@win.shown?
75
+ @selected = value
76
+ end
77
+
78
+ #
79
+ # Change direction of connection
80
+ #
81
+ def toggle_direction
82
+ # If a self-loop, we cannot change dir
83
+ return if @room[0] == @room[1] and
84
+ @room[0].exits.index(self) == @room[0].exits.rindex(self)
85
+
86
+ @dir ^= 1
87
+ @@win.copy_from(self) if @@win
88
+ end
89
+
90
+ #
91
+ # Is this a complex path. Check if connection is
92
+ # contiguous
93
+ #
94
+ def complex?()
95
+ return false if not @room[1]
96
+ return true if @room[1] == @room[0]
97
+ return true unless @room[0].next_to?(@room[1])
98
+
99
+ # Even if rooms are next to each other, we need to
100
+ # verify that following the exits does indeed take us to next room.
101
+ exitA = @room[0].exits.index(self)
102
+ dir = Room::DIR_TO_VECTOR[exitA]
103
+
104
+ if @room[0].x + dir[0] == @room[1].x and
105
+ @room[0].y + dir[1] == @room[1].y
106
+ exitB = @room[1].exits.rindex(self)
107
+ dir = Room::DIR_TO_VECTOR[exitB]
108
+ if @room[1].x + dir[0] == @room[0].x and
109
+ @room[1].y + dir[1] == @room[0].y
110
+ return false
111
+ else
112
+ return true
113
+ end
114
+ else
115
+ return true
116
+ end
117
+ end
118
+
119
+ #
120
+ # Main draw function
121
+ #
122
+ def draw(dc, zoom, opt)
123
+ if @selected
124
+ dc.foreground = 'yellow'
125
+ elsif @failed
126
+ dc.foreground = 'red'
127
+ else
128
+ dc.foreground = opt['Arrow Color']
129
+ end
130
+
131
+ draw_exit_text(dc, zoom)
132
+ if @type == SPECIAL
133
+ dc.lineStyle = LINE_ONOFF_DASH
134
+ else
135
+ dc.lineStyle = LINE_SOLID
136
+ end
137
+ if pts.size > 0
138
+ draw_complex(dc, zoom, opt)
139
+ else
140
+ draw_simple(dc, zoom)
141
+ end
142
+ end
143
+
144
+
145
+ def update_properties(map)
146
+ return if not @@win or not @@win.shown?
147
+ @@win.map = map
148
+ @@win.copy_from(self)
149
+ end
150
+
151
+ def properties(map, event = nil)
152
+ if not @@win
153
+ @@win = FXConnectionDialogBox.new(map, self, event)
154
+ end
155
+ @@win.show
156
+ update_properties(map)
157
+ end
158
+
159
+ protected
160
+
161
+ RAD_45 = 45 * Math::PI / 180
162
+ SIN_45 = Math.sin(RAD_45)
163
+ COS_45 = Math.cos(RAD_45)
164
+
165
+ def _arrow_info( x1, y1, x2, y2, zoom = 1.0 )
166
+ pt1 = []
167
+ dir = 0
168
+ dir = @room[1].exits.rindex(self)
169
+ pt1 = [ x2, y2 ]
170
+ x, y = Room::DIR_TO_VECTOR[dir]
171
+ if @room[0] == @room[1]
172
+ size = 15.0
173
+ else
174
+ size = 20.0
175
+ end
176
+ arrow_len = size / Math.sqrt(x * x + y * y)
177
+ x *= arrow_len * zoom
178
+ y *= arrow_len * -zoom
179
+
180
+ d = [
181
+ x * COS_45 + y * SIN_45,
182
+ x * SIN_45 - y * COS_45
183
+ ]
184
+ return pt1, d
185
+ end
186
+
187
+
188
+ #
189
+ # Draw a complex connection as a line path
190
+ #
191
+ def draw_complex_as_lines(dc, zoom)
192
+ p = []
193
+ @pts.each { |pt|
194
+ p << FXPoint.new( (pt[0] * zoom).to_i, (pt[1] * zoom).to_i )
195
+ }
196
+ dc.drawLines( p )
197
+ return p
198
+ end
199
+
200
+ #
201
+ # Draw a complex connection as a bspline path
202
+ #
203
+ def draw_complex_as_bspline(dc, zoom)
204
+ p = []
205
+ p << [ @pts[0][0] * zoom, @pts[0][1] * zoom ]
206
+ p << p[0]
207
+ p << p[0]
208
+ @pts.each { |pt|
209
+ p << [ pt[0] * zoom, pt[1] * zoom ]
210
+ }
211
+ p << p[-1]
212
+ p << p[-1]
213
+ p << p[-1]
214
+ return dc.drawBSpline( p )
215
+ end
216
+
217
+ #
218
+ # Draw a door
219
+ #
220
+ def draw_door(dc, zoom, x1, y1, x2, y2)
221
+ v = [ (x2-x1), (y2-y1) ]
222
+ t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
223
+ v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
224
+ m = [ (x2+x1)/2, (y2+y1)/2 ]
225
+ x1, y1 = [m[0] + v[1], m[1] - v[0]]
226
+ x2, y2 = [m[0] - v[1], m[1] + v[0]]
227
+ if @type == LOCKED_DOOR
228
+ # Locked door
229
+ dc.drawLine(x1, y1, x2, y2)
230
+ else
231
+ # open door
232
+ v = [ v[0] / 3, v[1] / 3]
233
+ x1, y1 = x1.to_i, y1.to_i
234
+ x2, y2 = x2.to_i, y2.to_i
235
+ pts = []
236
+ pts << FXPoint.new(x1 - v[0], y1 - v[1])
237
+ pts << FXPoint.new(x1 + v[0], y1 + v[1])
238
+ pts << FXPoint.new(x2 + v[0], y2 + v[1])
239
+ pts << FXPoint.new(x2 - v[0], y2 - v[1])
240
+ pts << pts[0]
241
+ width = dc.lineWidth
242
+ dc.lineWidth = 0
243
+ dc.drawLines(pts)
244
+ dc.lineWidth = width
245
+ end
246
+ end
247
+
248
+ #
249
+ # Draw a complex connection
250
+ #
251
+ def draw_complex(dc, zoom, opt)
252
+ if opt['Paths as Curves']
253
+ if @room[0] == @room[1]
254
+ dirA, dirB = dirs
255
+ if dirA == dirB
256
+ p = draw_complex_as_lines(dc, zoom)
257
+ else
258
+ p = draw_complex_as_bspline(dc, zoom)
259
+ end
260
+ else
261
+ p = draw_complex_as_bspline(dc, zoom)
262
+ end
263
+ else
264
+ p = draw_complex_as_lines(dc, zoom)
265
+ end
266
+
267
+ x1, y1 = [p[0].x, p[0].y]
268
+ x2, y2 = [p[-1].x, p[-1].y]
269
+ draw_arrow(dc, zoom, x1, y1, x2, y2)
270
+
271
+ if @type == LOCKED_DOOR or @type == CLOSED_DOOR
272
+ t = p.size / 2
273
+ x1, y1 = [ p[t].x, p[t].y ]
274
+ x2, y2 = [ p[t-2].x, p[t-2].y ]
275
+ draw_door(dc, zoom, x1, y1, x2, y2)
276
+ end
277
+ end
278
+
279
+ #
280
+ # Draw a simple connection. Simple connections are straight
281
+ # line connections or 'stub' connections.
282
+ #
283
+ def draw_simple(dc, zoom)
284
+ dir = @room[0].exits.index(self)
285
+ x1, y1 = @room[0].corner(self, zoom, dir)
286
+ if @room[1]
287
+ x2, y2 = @room[1].corner(self, zoom)
288
+ dc.drawLine( x1, y1, x2, y2 )
289
+ draw_arrow(dc, zoom, x1, y1, x2, y2)
290
+ if @type == LOCKED_DOOR or @type == CLOSED_DOOR
291
+ draw_door(dc, zoom, x1, y1, x2, y2)
292
+ end
293
+ else
294
+ # Complex connection in progress or "stub" exit
295
+ v = FXRoom::DIR_TO_VECTOR[dir]
296
+ x2, y2 = [ x1 + v[0] * WS * zoom * 0.4, y1 + v[1] * HS * zoom * 0.4 ]
297
+ dc.drawLine( x1, y1, x2, y2 )
298
+ end
299
+ end
300
+
301
+
302
+ #
303
+ # Draw an arrow at one end of the path
304
+ #
305
+ def draw_arrow( dc, zoom, x1, y1, x2, y2 )
306
+ return if @dir == BOTH
307
+ pt1, d = _arrow_info( x1, y1, x2, y2, zoom )
308
+
309
+ p = []
310
+ p << FXPoint.new( pt1[0].to_i, pt1[1].to_i )
311
+ pt2 = [ pt1[0] + d[0], pt1[1] + d[1] ]
312
+ p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
313
+ pt2 = [ pt1[0] + d[1], pt1[1] - d[0] ]
314
+ p << FXPoint.new( pt2[0].to_i, pt2[1].to_i )
315
+
316
+ dc.fillPolygon(p)
317
+ end
318
+
319
+ #
320
+ # Draw the connection text next to the arrow ('I', 'O', etc)
321
+ #
322
+ def draw_text(dc, zoom, x, y, dir, text, arrow)
323
+ if dir == 7 or dir < 6 and dir != 1
324
+ if arrow and (dir == 0 or dir == 4)
325
+ x += 10 * zoom
326
+ end
327
+ x += 5 * zoom
328
+ elsif dir == 6 or dir == 1
329
+ x -= 15 * zoom
330
+ end
331
+
332
+ if dir > 5 or dir < 4
333
+ if arrow and (dir == 6 or dir == 2)
334
+ y -= 10 * zoom
335
+ end
336
+ y -= 5 * zoom
337
+ elsif dir == 4 or dir == 5
338
+ y += 15 * zoom
339
+ end
340
+
341
+ dc.drawText(x, y, text)
342
+ end
343
+
344
+ #
345
+ # Draw any exit text if available (exit text is 'U', 'D', 'I', 'O', etc)
346
+ #
347
+ def draw_exit_text(dc, zoom)
348
+ return if zoom < 0.5
349
+ if @exitText[0] != 0
350
+ dir = @room[0].exits.index(self)
351
+ x, y = @room[0].corner(self, zoom, dir)
352
+ draw_text( dc, zoom, x, y, dir,
353
+ DRAW_EXIT_TEXT[@exitText[0]], nil )
354
+ end
355
+ if @exitText[1] != 0
356
+ dir = @room[1].exits.rindex(self)
357
+ x, y = @room[1].corner(self, zoom, dir)
358
+ draw_text( dc, zoom, x, y, dir,
359
+ DRAW_EXIT_TEXT[@exitText[1]], @dir == AtoB)
360
+ end
361
+ end
362
+
363
+ end
364
+