ifmapper 0.5 → 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +26 -0
- data/IFMapper.gemspec +1 -1
- data/icons/room_e.gif +0 -0
- data/icons/room_e.xpm +39 -0
- data/icons/room_n.gif +0 -0
- data/icons/room_n.xpm +40 -0
- data/icons/room_ne.gif +0 -0
- data/icons/room_ne.xpm +80 -0
- data/icons/room_nw.gif +0 -0
- data/icons/room_nw.xpm +80 -0
- data/icons/room_s.gif +0 -0
- data/icons/room_s.xpm +40 -0
- data/icons/room_se.gif +0 -0
- data/icons/room_se.xpm +80 -0
- data/icons/room_sw.gif +0 -0
- data/icons/room_sw.xpm +80 -0
- data/icons/room_w.gif +0 -0
- data/icons/room_w.xpm +39 -0
- data/lib/IFMapper/AStar.rb +243 -0
- data/lib/IFMapper/FXConnection.rb +101 -72
- data/lib/IFMapper/FXMap.rb +155 -230
- data/lib/IFMapper/FXMapColorBox.rb +92 -0
- data/lib/IFMapper/FXMapDialogBox.rb +83 -7
- data/lib/IFMapper/FXMapperSettings.rb +1 -0
- data/lib/IFMapper/FXMapperWindow.rb +82 -48
- data/lib/IFMapper/FXRoom.rb +43 -17
- data/lib/IFMapper/{FXPage.rb → FXSection.rb} +3 -3
- data/lib/IFMapper/{FXPageDialogBox.rb → FXSectionDialogBox.rb} +6 -6
- data/lib/IFMapper/FXSpline.rb +10 -14
- data/lib/IFMapper/IFMReader.rb +39 -31
- data/lib/IFMapper/Map.rb +42 -43
- data/lib/IFMapper/MapPrinting.rb +161 -0
- data/lib/IFMapper/PDFMapExporter.rb +128 -51
- data/lib/IFMapper/Room.rb +11 -1
- data/lib/IFMapper/{Page.rb → Section.rb} +65 -42
- metadata +34 -15
data/icons/room_w.gif
ADDED
Binary file
|
data/icons/room_w.xpm
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
/* XPM */
|
2
|
+
static char * room_left_xpm[] = {
|
3
|
+
"32 32 4 1",
|
4
|
+
" c #000000",
|
5
|
+
". c #404040",
|
6
|
+
"+ c #7F7F7F",
|
7
|
+
"@ c #FFFFFF",
|
8
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
9
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
10
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
11
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
12
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
13
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
14
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
15
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
16
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
17
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
18
|
+
"@@@@@@@@.++++++++++++++.@@@@@@@@",
|
19
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
20
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
21
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
22
|
+
"@ @@@@@@@@@@@@@@+@@@@@@@@",
|
23
|
+
"@ @@@@@@@@@@@@@@+@@@@@@@@",
|
24
|
+
"@ @@@@@@@@@@@@@@+@@@@@@@@",
|
25
|
+
"@ @@@@@@@@@@@@@@+@@@@@@@@",
|
26
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
27
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
28
|
+
"@@@@@@@@+@@@@@@@@@@@@@@+@@@@@@@@",
|
29
|
+
"@@@@@@@@.++++++++++++++.@@@@@@@@",
|
30
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
31
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
32
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
33
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
34
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
35
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
36
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
37
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
38
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@",
|
39
|
+
"@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"};
|
@@ -0,0 +1,243 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
#
|
5
|
+
# A class used for path finding.
|
6
|
+
# This is largely based on C++ code by Justin Heyes-Jones, albeit simplified
|
7
|
+
#
|
8
|
+
class AStar
|
9
|
+
|
10
|
+
attr :start, :goal
|
11
|
+
attr_reader :state
|
12
|
+
attr :successors
|
13
|
+
attr :open_list
|
14
|
+
attr :closed_list
|
15
|
+
|
16
|
+
SEARCH_STATE_NOT_INITIALIZED = 0
|
17
|
+
SEARCH_STATE_SEARCHING = 1
|
18
|
+
SEARCH_STATE_SUCCEEDED = 2
|
19
|
+
SEARCH_STATE_FAILED = 3
|
20
|
+
|
21
|
+
def open_list
|
22
|
+
puts "Open List:"
|
23
|
+
@open_list.each { |n|
|
24
|
+
p n
|
25
|
+
}
|
26
|
+
puts "Closed List # of nodes: #{@open_list.size}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def closed_list
|
30
|
+
puts "Closed List:"
|
31
|
+
@closed_list.each { |n|
|
32
|
+
p n
|
33
|
+
}
|
34
|
+
puts "Closed List # of nodes: #{@closed_list.size}"
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class Node
|
39
|
+
attr_accessor :parent, :child
|
40
|
+
attr_accessor :h, :g, :f
|
41
|
+
|
42
|
+
attr_reader :info
|
43
|
+
|
44
|
+
def <=>(b)
|
45
|
+
return -1 if @f > b.f
|
46
|
+
return 0 if @f == b.f
|
47
|
+
return 1
|
48
|
+
end
|
49
|
+
|
50
|
+
def inspect
|
51
|
+
"AStarNode: #{@f} = #{@g} + #{@h} #{@info.inspect}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def initialize( info = nil )
|
55
|
+
@h = @g = @f = 0.0
|
56
|
+
@info = info
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# sets start and end goals and initializes A* search
|
61
|
+
def goals( start, goal )
|
62
|
+
@start = Node.new( start )
|
63
|
+
@start.g = 0.0
|
64
|
+
@start.h = start.distance_estimate( goal )
|
65
|
+
@start.f = @start.h
|
66
|
+
|
67
|
+
@open_list = []
|
68
|
+
@open_list.push( @start )
|
69
|
+
@closed_list = []
|
70
|
+
|
71
|
+
@goal = Node.new( goal )
|
72
|
+
|
73
|
+
@state = SEARCH_STATE_SEARCHING
|
74
|
+
end
|
75
|
+
|
76
|
+
# Advances one search step
|
77
|
+
def search_step
|
78
|
+
if @open_list.empty?
|
79
|
+
@state = SEARCH_STATE_FAILED
|
80
|
+
return @state
|
81
|
+
end
|
82
|
+
|
83
|
+
# Pop the best node (the one with the lowest f)
|
84
|
+
n = @open_list.pop
|
85
|
+
|
86
|
+
# Check for the goal. Once we pop that, we are done
|
87
|
+
if n.info.is_goal?( @goal.info )
|
88
|
+
# The user is going to use the Goal Node he passed in
|
89
|
+
# so copy the parent pointer of n
|
90
|
+
@goal.parent = n.parent
|
91
|
+
# Special case is that the goal was passed in as the start state
|
92
|
+
# so handle that here
|
93
|
+
if n != @start
|
94
|
+
child = @goal
|
95
|
+
parent = @goal.parent
|
96
|
+
|
97
|
+
while child != @start
|
98
|
+
parent.child = child
|
99
|
+
child = parent
|
100
|
+
parent = parent.parent
|
101
|
+
end
|
102
|
+
end
|
103
|
+
@state = SEARCH_STATE_SUCCEEDED
|
104
|
+
return @state
|
105
|
+
else
|
106
|
+
# Not goal, get successors
|
107
|
+
n.info.successors( self, n.parent )
|
108
|
+
@successors.each { |s|
|
109
|
+
newg = n.g + n.info.cost( s.info )
|
110
|
+
|
111
|
+
# Now, we need to find out if this node is on the open or close lists
|
112
|
+
# If it is, but the node that is already on them is better (lower g)
|
113
|
+
# then we can forget about this successor
|
114
|
+
open = @open_list.find { |e| e.info.is_same?( s.info ) }
|
115
|
+
# State in open list is cheaper than this successor
|
116
|
+
next if open and open.g <= newg
|
117
|
+
|
118
|
+
closed = @closed_list.find { |e| e.info.is_same?( s.info ) }
|
119
|
+
# We found a cheaper state in closed list
|
120
|
+
next if closed and closed.g <= newg
|
121
|
+
|
122
|
+
# This node is the best node so far so let's keep it and set up
|
123
|
+
# its A* specific data
|
124
|
+
s.parent = n
|
125
|
+
s.g = newg
|
126
|
+
s.h = s.info.distance_estimate( @goal.info )
|
127
|
+
s.f = s.g + s.h
|
128
|
+
|
129
|
+
# Remove succesor from closed list if it was on it
|
130
|
+
@closed_list.delete(closed) if closed
|
131
|
+
# Remove succesor from open list if it was on it
|
132
|
+
@open_list.delete(open) if open
|
133
|
+
@open_list.push(s)
|
134
|
+
# Make sure open list stays sorted based on f
|
135
|
+
@open_list.sort!
|
136
|
+
}
|
137
|
+
@closed_list.push(n)
|
138
|
+
@successors.clear
|
139
|
+
end
|
140
|
+
return @state
|
141
|
+
end
|
142
|
+
|
143
|
+
def add_successor( info )
|
144
|
+
@successors << Node.new(info)
|
145
|
+
end
|
146
|
+
|
147
|
+
# return solution as an path (ie. an array of [x,y] coordinates)
|
148
|
+
def path
|
149
|
+
p = []
|
150
|
+
curr = @start
|
151
|
+
while curr
|
152
|
+
p << [curr.info.x, curr.info.y]
|
153
|
+
curr = curr.child
|
154
|
+
end
|
155
|
+
return p
|
156
|
+
end
|
157
|
+
|
158
|
+
def initialize
|
159
|
+
@state = SEARCH_STATE_NOT_INITIALIZED
|
160
|
+
@successors = []
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
#
|
166
|
+
# Simple class used as a
|
167
|
+
#
|
168
|
+
class MapNode
|
169
|
+
attr_reader :x, :y
|
170
|
+
@@pmap = nil
|
171
|
+
|
172
|
+
def self.map(pmap)
|
173
|
+
@@pmap = pmap
|
174
|
+
end
|
175
|
+
|
176
|
+
def initialize(x, y)
|
177
|
+
@x = x
|
178
|
+
@y = y
|
179
|
+
end
|
180
|
+
|
181
|
+
def is_same?(node)
|
182
|
+
return true if node and @x == node.x and @y == node.y
|
183
|
+
return false
|
184
|
+
end
|
185
|
+
|
186
|
+
def is_goal?( goal )
|
187
|
+
return true if @x == goal.x and @y == goal.y
|
188
|
+
return false
|
189
|
+
end
|
190
|
+
|
191
|
+
def distance_estimate( goal )
|
192
|
+
dx = @x - goal.x
|
193
|
+
dy = @y - goal.y
|
194
|
+
return dx*dx + dy*dy
|
195
|
+
end
|
196
|
+
|
197
|
+
MAX_SCALE = 9
|
198
|
+
|
199
|
+
def get_map(x, y)
|
200
|
+
if x < 0 or y < 0 or x >= @@pmap.size or y >= @@pmap[0].size
|
201
|
+
return MAX_SCALE
|
202
|
+
else
|
203
|
+
t = @@pmap[x][y]
|
204
|
+
return MAX_SCALE if t.kind_of?(Room)
|
205
|
+
return MAX_SCALE-1 if t.kind_of?(Connection)
|
206
|
+
return 1
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def successors( astar, parent = nil )
|
211
|
+
info = nil
|
212
|
+
info = parent.info if parent
|
213
|
+
Room::DIR_TO_VECTOR.each_value { |x, y|
|
214
|
+
new_node = MapNode.new(@x + x, @y + y)
|
215
|
+
if get_map( new_node.x, new_node.y ) < MAX_SCALE and
|
216
|
+
not new_node.is_same?(info)
|
217
|
+
astar.add_successor(new_node)
|
218
|
+
end
|
219
|
+
}
|
220
|
+
end
|
221
|
+
|
222
|
+
def inspect
|
223
|
+
"pos: #{@x}, #{@y}"
|
224
|
+
end
|
225
|
+
|
226
|
+
def to_s
|
227
|
+
inspect
|
228
|
+
end
|
229
|
+
|
230
|
+
def cost( successor )
|
231
|
+
g = get_map(@x,@y)
|
232
|
+
|
233
|
+
# dx = (@x - successor.x).abs
|
234
|
+
# dy = (@y - successor.y).abs
|
235
|
+
# if dx + dy == 1
|
236
|
+
# g += 0 # straight move
|
237
|
+
# else
|
238
|
+
# g += 4 # diagonal move
|
239
|
+
# end
|
240
|
+
return g
|
241
|
+
end
|
242
|
+
|
243
|
+
end
|
@@ -55,27 +55,27 @@ class FXConnection < Connection
|
|
55
55
|
[ @selected, @type, @dir, @roomA, @roomB, @exitAtext, @exitBtext ]
|
56
56
|
end
|
57
57
|
|
58
|
+
#
|
59
|
+
# Change selection state of connection. If Connection Properties
|
60
|
+
# window is open, copy the connection data to it.
|
61
|
+
#
|
58
62
|
def selected=(value)
|
59
|
-
if value and @@win
|
60
|
-
@@win.copy_from(self)
|
61
|
-
end
|
63
|
+
@@win.copy_from(self) if value and @@win
|
62
64
|
@selected = value
|
63
65
|
end
|
64
66
|
|
67
|
+
#
|
68
|
+
# Change direction of connection
|
69
|
+
#
|
65
70
|
def toggle_direction
|
66
71
|
# If a self-loop, we cannot change dir
|
67
|
-
if @roomA == @roomB
|
68
|
-
|
69
|
-
end
|
72
|
+
return if @roomA == @roomB and
|
73
|
+
@roomA.exits.index(self) == @roomA.exits.rindex(self)
|
70
74
|
|
71
75
|
@dir += 1
|
72
|
-
if @dir > BtoA
|
73
|
-
@dir = BOTH
|
74
|
-
end
|
76
|
+
@dir = BOTH if @dir > BtoA
|
75
77
|
|
76
|
-
if @@win
|
77
|
-
@@win.copy_from(self)
|
78
|
-
end
|
78
|
+
@@win.copy_from(self) if @@win
|
79
79
|
end
|
80
80
|
|
81
81
|
#
|
@@ -107,6 +107,75 @@ class FXConnection < Connection
|
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
110
|
+
#
|
111
|
+
# Main draw function
|
112
|
+
#
|
113
|
+
def draw(dc, zoom, opt)
|
114
|
+
if @selected
|
115
|
+
dc.foreground = 'yellow'
|
116
|
+
elsif @failed
|
117
|
+
dc.foreground = 'red'
|
118
|
+
else
|
119
|
+
dc.foreground = opt['Arrow Color']
|
120
|
+
end
|
121
|
+
|
122
|
+
draw_exit_text(dc, zoom)
|
123
|
+
if @type == SPECIAL
|
124
|
+
dc.lineStyle = LINE_ONOFF_DASH
|
125
|
+
else
|
126
|
+
dc.lineStyle = LINE_SOLID
|
127
|
+
end
|
128
|
+
if pts.size > 0
|
129
|
+
draw_complex(dc, zoom, opt)
|
130
|
+
else
|
131
|
+
draw_simple(dc, zoom)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
def properties(map, event = nil)
|
137
|
+
if not @@win
|
138
|
+
@@win = FXConnectionDialogBox.new(map, self, event)
|
139
|
+
else
|
140
|
+
@@win.map = map
|
141
|
+
end
|
142
|
+
@@win.copy_from(self)
|
143
|
+
@@win.show
|
144
|
+
return
|
145
|
+
end
|
146
|
+
|
147
|
+
protected
|
148
|
+
|
149
|
+
RAD_45 = 45 * Math::PI / 180
|
150
|
+
SIN_45 = Math.sin(RAD_45)
|
151
|
+
COS_45 = Math.cos(RAD_45)
|
152
|
+
|
153
|
+
def _arrow_info( x1, y1, x2, y2, zoom = 1.0 )
|
154
|
+
pt1 = []
|
155
|
+
dir = 0
|
156
|
+
if @dir == AtoB
|
157
|
+
dir = @roomB.exits.rindex(self)
|
158
|
+
pt1 = [ x2, y2 ]
|
159
|
+
else
|
160
|
+
dir = @roomA.exits.index(self)
|
161
|
+
pt1 = [ x1, y1 ]
|
162
|
+
end
|
163
|
+
x, y = Room::DIR_TO_VECTOR[dir]
|
164
|
+
arrow_len = 20.0 / Math.sqrt(x * x + y * y)
|
165
|
+
x *= arrow_len * zoom
|
166
|
+
y *= arrow_len * -zoom
|
167
|
+
|
168
|
+
d = [
|
169
|
+
x * COS_45 + y * SIN_45,
|
170
|
+
x * SIN_45 - y * COS_45
|
171
|
+
]
|
172
|
+
return pt1, d
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
#
|
177
|
+
# Draw a complex connection as a line path
|
178
|
+
#
|
110
179
|
def draw_complex_as_lines(dc, zoom)
|
111
180
|
p = []
|
112
181
|
@pts.each { |pt|
|
@@ -116,6 +185,9 @@ class FXConnection < Connection
|
|
116
185
|
return p
|
117
186
|
end
|
118
187
|
|
188
|
+
#
|
189
|
+
# Draw a complex connection as a bspline path
|
190
|
+
#
|
119
191
|
def draw_complex_as_bspline(dc, zoom)
|
120
192
|
p = []
|
121
193
|
p << [ @pts[0][0] * zoom, @pts[0][1] * zoom ]
|
@@ -130,6 +202,9 @@ class FXConnection < Connection
|
|
130
202
|
return dc.drawBSpline( p )
|
131
203
|
end
|
132
204
|
|
205
|
+
#
|
206
|
+
# Draw a complex connection
|
207
|
+
#
|
133
208
|
def draw_complex(dc, zoom, opt)
|
134
209
|
if opt['Paths as Curves']
|
135
210
|
p = draw_complex_as_bspline(dc, zoom)
|
@@ -142,6 +217,10 @@ class FXConnection < Connection
|
|
142
217
|
draw_arrow(dc, zoom, x1, y1, x2, y2)
|
143
218
|
end
|
144
219
|
|
220
|
+
#
|
221
|
+
# Draw a simple connection. Simple connections are straight
|
222
|
+
# line connections or 'stub' connections.
|
223
|
+
#
|
145
224
|
def draw_simple(dc, zoom)
|
146
225
|
dir = @roomA.exits.index(self)
|
147
226
|
x1, y1 = @roomA.corner(self, zoom, dir)
|
@@ -157,6 +236,7 @@ class FXConnection < Connection
|
|
157
236
|
dc.drawLine(x1, y1, x2, y2)
|
158
237
|
end
|
159
238
|
else
|
239
|
+
# Complex connection in progress or "stub" exit
|
160
240
|
v = FXRoom::DIR_TO_VECTOR[dir]
|
161
241
|
x2, y2 = [ @roomA.x + v[0] * 0.5, @roomA.y + v[1] * 0.5 ]
|
162
242
|
x2 *= WW * zoom
|
@@ -167,33 +247,10 @@ class FXConnection < Connection
|
|
167
247
|
end
|
168
248
|
end
|
169
249
|
|
170
|
-
RAD_45 = 45 * Math::PI / 180
|
171
|
-
SIN_45 = Math.sin(RAD_45)
|
172
|
-
COS_45 = Math.cos(RAD_45)
|
173
|
-
|
174
|
-
def _arrow_info( x1, y1, x2, y2, zoom = 1.0 )
|
175
|
-
pt1 = []
|
176
|
-
dir = 0
|
177
|
-
if @dir == AtoB
|
178
|
-
dir = @roomB.exits.rindex(self)
|
179
|
-
pt1 = [ x2, y2 ]
|
180
|
-
else
|
181
|
-
dir = @roomA.exits.index(self)
|
182
|
-
pt1 = [ x1, y1 ]
|
183
|
-
end
|
184
|
-
x, y = Room::DIR_TO_VECTOR[dir]
|
185
|
-
arrow_len = 20.0 / Math.sqrt(x * x + y * y)
|
186
|
-
x *= arrow_len * zoom
|
187
|
-
y *= arrow_len * -zoom
|
188
|
-
|
189
|
-
d = [
|
190
|
-
x * COS_45 + y * SIN_45,
|
191
|
-
x * SIN_45 - y * COS_45
|
192
|
-
]
|
193
|
-
return pt1, d
|
194
|
-
end
|
195
|
-
|
196
250
|
|
251
|
+
#
|
252
|
+
# Draw an arrow at one end of the path
|
253
|
+
#
|
197
254
|
def draw_arrow( dc, zoom, x1, y1, x2, y2 )
|
198
255
|
return if @dir == BOTH
|
199
256
|
pt1, d = _arrow_info( x1, y1, x2, y2, zoom )
|
@@ -208,6 +265,9 @@ class FXConnection < Connection
|
|
208
265
|
dc.fillPolygon(p)
|
209
266
|
end
|
210
267
|
|
268
|
+
#
|
269
|
+
# Draw the connection text next to the arrow ('I', 'O', etc)
|
270
|
+
#
|
211
271
|
def draw_text(dc, zoom, x, y, dir, text, arrow)
|
212
272
|
if dir == 7 or dir < 6 and dir != 1
|
213
273
|
if arrow and (dir == 0 or dir == 4)
|
@@ -230,6 +290,9 @@ class FXConnection < Connection
|
|
230
290
|
dc.drawText(x, y, text)
|
231
291
|
end
|
232
292
|
|
293
|
+
#
|
294
|
+
# Draw any exit text if available (exit text is 'U', 'D', 'I', 'O', etc)
|
295
|
+
#
|
233
296
|
def draw_exit_text(dc, zoom)
|
234
297
|
if @exitAtext != 0
|
235
298
|
dir = @roomA.exits.index(self)
|
@@ -245,39 +308,5 @@ class FXConnection < Connection
|
|
245
308
|
end
|
246
309
|
end
|
247
310
|
|
248
|
-
def draw(dc, zoom, opt)
|
249
|
-
if @selected
|
250
|
-
dc.foreground = 'yellow'
|
251
|
-
elsif @failed
|
252
|
-
dc.foreground = 'red'
|
253
|
-
else
|
254
|
-
dc.foreground = opt['Arrow Color']
|
255
|
-
end
|
256
|
-
|
257
|
-
draw_exit_text(dc, zoom)
|
258
|
-
if @type == SPECIAL
|
259
|
-
dc.lineStyle = LINE_ONOFF_DASH
|
260
|
-
else
|
261
|
-
dc.lineStyle = LINE_SOLID
|
262
|
-
end
|
263
|
-
if pts.size > 0
|
264
|
-
draw_complex(dc, zoom, opt)
|
265
|
-
else
|
266
|
-
draw_simple(dc, zoom)
|
267
|
-
end
|
268
|
-
end
|
269
|
-
|
270
|
-
|
271
|
-
def properties(map, event = nil)
|
272
|
-
if not @@win
|
273
|
-
@@win = FXConnectionDialogBox.new(map, self, event)
|
274
|
-
else
|
275
|
-
@@win.map = map
|
276
|
-
end
|
277
|
-
@@win.copy_from(self)
|
278
|
-
@@win.show
|
279
|
-
return
|
280
|
-
end
|
281
|
-
|
282
311
|
end
|
283
312
|
|