ifmapper 1.0.0 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/HISTORY.txt +648 -627
- data/IFMapper.gemspec +29 -28
- data/IFMapper.rbw +31 -31
- data/TODO.txt +8 -7
- data/bin/IFMapper +31 -31
- data/docs/en/index.html +0 -0
- data/docs/en/start.html +3 -2
- data/docs/en/start.html~ +516 -0
- data/docs/es/index.html +0 -0
- data/docs/es/start.html +13 -14
- data/docs/es/start.html~ +1280 -0
- data/docs/images/IFMapper_main.gif +0 -0
- data/docs/images/automap.gif +0 -0
- data/docs/images/complex_connection.gif +0 -0
- data/docs/images/connection.gif +0 -0
- data/docs/images/connection_menu.gif +0 -0
- data/docs/images/room_description.gif +0 -0
- data/docs/images/room_small.gif +0 -0
- data/icons/copy.png +0 -0
- data/icons/cut.png +0 -0
- data/icons/filenew.png +0 -0
- data/icons/fileopen.png +0 -0
- data/icons/filesave.png +0 -0
- data/icons/filesaveas.png +0 -0
- data/icons/help.png +0 -0
- data/icons/kill.png +0 -0
- data/icons/nextpage.png +0 -0
- data/icons/paste.png +0 -0
- data/icons/prevpage.png +0 -0
- data/icons/printicon.png +0 -0
- data/icons/redo.png +0 -0
- data/icons/room_e.gif +0 -0
- data/icons/room_e.xpm +0 -0
- data/icons/room_n.gif +0 -0
- data/icons/room_n.xpm +0 -0
- data/icons/room_ne.gif +0 -0
- data/icons/room_ne.xpm +0 -0
- data/icons/room_nw.gif +0 -0
- data/icons/room_nw.xpm +0 -0
- data/icons/room_s.gif +0 -0
- data/icons/room_s.xpm +0 -0
- data/icons/room_se.gif +0 -0
- data/icons/room_se.xpm +0 -0
- data/icons/room_sw.gif +0 -0
- data/icons/room_sw.xpm +0 -0
- data/icons/room_w.gif +0 -0
- data/icons/room_w.xpm +0 -0
- data/icons/saveas.png +0 -0
- data/icons/undo.png +0 -0
- data/icons/winapp.png +0 -0
- data/icons/zoom.png +0 -0
- data/lib/IFMapper/AStar.rb +250 -250
- data/lib/IFMapper/Connection.rb +202 -202
- data/lib/IFMapper/FXAboutDialogBox.rb +32 -32
- data/lib/IFMapper/FXConnection.rb +364 -364
- data/lib/IFMapper/FXConnectionDialogBox.rb +124 -124
- data/lib/IFMapper/FXDCPostscript.rb +404 -404
- data/lib/IFMapper/FXDCPrint.rb +15 -15
- data/lib/IFMapper/FXItemList.rb +108 -0
- data/lib/IFMapper/FXMap.rb +2147 -2116
- data/lib/IFMapper/FXMapColorBox.rb +88 -88
- data/lib/IFMapper/FXMapDialogBox.rb +127 -127
- data/lib/IFMapper/FXMapFileDialog.rb +34 -34
- data/lib/IFMapper/FXMapperSettings.rb +206 -205
- data/lib/IFMapper/FXMapperWindow.rb +1592 -1571
- data/lib/IFMapper/FXPDFMapExporterOptionsDialogBox.rb +46 -0
- data/lib/IFMapper/FXRoom.rb +263 -263
- data/lib/IFMapper/FXRoomDialogBox.rb +159 -159
- data/lib/IFMapper/FXRoomList.rb +95 -95
- data/lib/IFMapper/FXSearchDialogBox.rb +51 -51
- data/lib/IFMapper/FXSection.rb +33 -33
- data/lib/IFMapper/FXSectionDialogBox.rb +38 -38
- data/lib/IFMapper/FXSpline.rb +52 -52
- data/lib/IFMapper/FXWarningBox.rb +51 -50
- data/lib/IFMapper/GUEReader.rb +445 -445
- data/lib/IFMapper/IFMReader.rb +584 -584
- data/lib/IFMapper/IFMWriter.rb +245 -227
- data/lib/IFMapper/Inform7Writer.rb +579 -573
- data/lib/IFMapper/InformReader.rb +478 -478
- data/lib/IFMapper/InformWriter.rb +364 -359
- data/lib/IFMapper/Map.rb +202 -200
- data/lib/IFMapper/MapPrinting.rb +162 -162
- data/lib/IFMapper/MapReader.rb +900 -900
- data/lib/IFMapper/PDFMapExporter.rb +526 -483
- data/lib/IFMapper/Room.rb +153 -151
- data/lib/IFMapper/Section.rb +234 -234
- data/lib/IFMapper/TADSReader.rb +474 -471
- data/lib/IFMapper/TADSWriter.rb +375 -370
- data/lib/IFMapper/TranscriptDialogBox.rb +0 -0
- data/lib/IFMapper/TranscriptReader.rb +1361 -1359
- data/lib/IFMapper/locales/en/Messages.rb +446 -435
- data/lib/IFMapper/locales/es/Messages.rb +451 -440
- data/lib/IFMapper/locales/es/Messages_iso-8859-1.rb +455 -440
- data/lib/IFMapper/locales/es/runme.sh +3 -3
- data/maps/A New Life.map b/data/maps/A New → Life.map +0 -0
- data/maps/AMFV.map +0 -0
- data/maps/AllRoads.map +0 -0
- data/maps/Aotearoa.map +0 -0
- data/maps/Bronze.map +0 -0
- data/maps/Bureaucracy.ifm +0 -0
- data/maps/Bureaucracy.map +0 -0
- data/maps/CityOfSecrets.map +0 -0
- data/maps/DDIV.map +0 -0
- data/maps/Following_A_Star.map +0 -0
- data/maps/Heated.map +0 -0
- data/maps/Heroine.map +0 -0
- data/maps/History Repeating.map b/data/maps/History → Repeating.map +0 -0
- data/maps/Hollywood_Hijinx.ifm +0 -0
- data/maps/Janitor.map +0 -0
- data/maps/Jigsaw.ifm +0 -0
- data/maps/Jigsaw.map +0 -0
- data/maps/LGOP.ifm +0 -0
- data/maps/Mercy.ifm +0 -0
- data/maps/Ninjas_Fate.map +0 -0
- data/maps/Pen_and_Paint.map +0 -0
- data/maps/Planetfall.ifm +0 -0
- data/maps/Planetfall.map +0 -0
- data/maps/Plundered_Hearts.ifm +0 -0
- data/maps/QuietEvening.map +0 -0
- data/maps/Ralph.ifm +0 -0
- data/maps/Reliques_of_Tolti_Alph.map +0 -0
- data/maps/Revolution.map +0 -0
- data/maps/Robots_of_Dawn.ifm +0 -0
- data/maps/SavoirFare.map +0 -0
- data/maps/Seastalker.ifm +0 -0
- data/maps/Seastalker.map +0 -0
- data/maps/Sherlock.ifm +0 -0
- data/maps/SoFar.ifm +0 -0
- data/maps/Starcross.ifm +0 -0
- data/maps/Suspended.ifm +0 -0
- data/maps/Tangle.map +0 -0
- data/maps/The_Lost_Sheep.map +0 -0
- data/maps/Unforgotten.map +0 -0
- data/maps/Warbler's Nest.map +0 -0
- data/maps/Warbler's_Nest.map +0 -0
- data/maps/Westminster_Abbey.map +0 -0
- data/maps/WinterWonderland.map +0 -0
- data/maps/Wishbringer.ifm +0 -0
- data/maps/Wishbringer2.ifm +0 -0
- data/maps/Zork1.ifm +0 -0
- data/maps/Zork2.ifm +0 -0
- data/maps/Zork3.ifm +0 -0
- data/maps/Zork_Zero.ifm +0 -0
- data/maps/anchor.ifm +0 -0
- data/maps/anchor.map +0 -0
- data/maps/atrox.ifm +0 -0
- data/maps/awaken.ifm +0 -0
- data/maps/babel.ifm +0 -0
- data/maps/balances.map +0 -0
- data/maps/ballerina.map +0 -0
- data/maps/bear.map +0 -0
- data/maps/bluechairs.map +0 -0
- data/maps/break_in.map +0 -0
- data/maps/bse.ifm +0 -0
- data/maps/building.map +0 -0
- data/maps/change.ifm +0 -0
- data/maps/christminster.map +0 -0
- data/maps/curses.ifm +0 -0
- data/maps/curves.ifm +0 -0
- data/maps/deadline.map +0 -0
- data/maps/delusions.map +0 -0
- data/maps/devours.map +0 -0
- data/maps/distress.map +0 -0
- data/maps/djinni.map +0 -0
- data/maps/dreamhold.map +0 -0
- data/maps/drift3.map +0 -0
- data/maps/eas.map +0 -0
- data/maps/eas2.map +0 -0
- data/maps/eas3.map +0 -0
- data/maps/edifice.ifm +0 -0
- data/maps/fallacy.map +0 -0
- data/maps/frozen.ifm +0 -0
- data/maps/gamlet.map +0 -0
- data/maps/glow.ifm +0 -0
- data/maps/guilty_bastards.map +0 -0
- data/maps/heist.map +0 -0
- data/maps/heroes.map +0 -0
- data/maps/inhumane.map +0 -0
- data/maps/kaged.map +0 -0
- data/maps/library.ifm +0 -0
- data/maps/lurkinghorror.map +0 -0
- data/maps/metamorphoses.map +0 -0
- data/maps/mindelec.ifm +0 -0
- data/maps/minster.ifm +0 -0
- data/maps/mite.map +0 -0
- data/maps/moonmist.map +0 -0
- data/maps/muldoon_legacy.map +0 -0
- data/maps/muse.ifm +0 -0
- data/maps/paperchase.ifm +0 -0
- data/maps/party.map +0 -0
- data/maps/pawn.map +0 -0
- data/maps/photograph.map +0 -0
- data/maps/pkgirl.map +0 -0
- data/maps/pytho.map +0 -0
- data/maps/risorgimento.map +0 -0
- data/maps/sherbet.map +0 -0
- data/maps/simple.map +0 -0
- data/maps/slouch.map +0 -0
- data/maps/space_st.ifm +0 -0
- data/maps/splashdown.map +0 -0
- data/maps/spring.map +0 -0
- data/maps/squarecircle.map +0 -0
- data/maps/stationfall.ifm +0 -0
- data/maps/theatre.ifm +0 -0
- data/maps/toonesia.ifm +0 -0
- data/maps/tortoise.ifm +0 -0
- data/maps/trinity.map +0 -0
- data/maps/vespers.map +0 -0
- data/maps/vgame.ifm +0 -0
- data/maps/wasp.map +0 -0
- data/maps/weather.ifm +0 -0
- data/maps/windhall.ifm +0 -0
- data/maps/worlds.map +0 -0
- data/maps/xtcontest.map +0 -0
- data/maps/zdungeon.map +0 -0
- data/maps/zebulon.ifm +0 -0
- data/maps/zerosum.map +0 -0
- metadata +226 -183
data/lib/IFMapper/FXDCPrint.rb
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
class FXDCPrint
|
|
3
|
-
alias :old_font= :font=
|
|
4
|
-
alias :old_font :font
|
|
5
|
-
|
|
6
|
-
def font
|
|
7
|
-
return @f
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def font=(x)
|
|
11
|
-
old_font=(x)
|
|
12
|
-
@f = x
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
end
|
|
1
|
+
|
|
2
|
+
class FXDCPrint
|
|
3
|
+
alias :old_font= :font=
|
|
4
|
+
alias :old_font :font
|
|
5
|
+
|
|
6
|
+
def font
|
|
7
|
+
return @f
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def font=(x)
|
|
11
|
+
old_font=(x)
|
|
12
|
+
@f = x
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
|
|
2
|
+
#
|
|
3
|
+
# Class that lists all rooms in a map and allows you to jump to them
|
|
4
|
+
#
|
|
5
|
+
class FXItemList < FXDialogBox
|
|
6
|
+
|
|
7
|
+
def pick(sender, sel, ptr)
|
|
8
|
+
it = @box.currentItem
|
|
9
|
+
name, section, room = @box.getItemData(it)
|
|
10
|
+
|
|
11
|
+
@map.section = section - 1
|
|
12
|
+
@map.clear_selection
|
|
13
|
+
room.selected = true
|
|
14
|
+
@map.center_view_on_room(room)
|
|
15
|
+
@map.draw
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def copy_from(map)
|
|
19
|
+
@map = map
|
|
20
|
+
sort
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def sort
|
|
24
|
+
it = @box.currentItem
|
|
25
|
+
room = nil
|
|
26
|
+
if it >= 0
|
|
27
|
+
item, section, room = @box.getItemData(it)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
@box.clearItems
|
|
31
|
+
|
|
32
|
+
items = []
|
|
33
|
+
@map.sections.each_with_index { |s, idx|
|
|
34
|
+
s.rooms.each { |r|
|
|
35
|
+
r.objects.each_line { |i|
|
|
36
|
+
i.chomp!
|
|
37
|
+
next if i.empty?
|
|
38
|
+
items << [i, idx+1, r ]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
dir = @box.header.getArrowDir(0)
|
|
44
|
+
if dir != MAYBE
|
|
45
|
+
items = items.sort_by { |r| r[0] }
|
|
46
|
+
else
|
|
47
|
+
dir = @box.header.getArrowDir(1)
|
|
48
|
+
if dir != MAYBE
|
|
49
|
+
items = items.sort_by { |r| r[1] }
|
|
50
|
+
else
|
|
51
|
+
dir = @box.header.getArrowDir(2)
|
|
52
|
+
if dir != MAYBE
|
|
53
|
+
items = items.sort_by { |r| r[2].name }
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
if dir == Fox::TRUE
|
|
59
|
+
items.reverse!
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
items.each { |r|
|
|
63
|
+
item = "#{r[0]}\t#{r[1]}\t#{r[2].name}"
|
|
64
|
+
@box.appendItem(item, nil, nil, r)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if room
|
|
68
|
+
items.each_with_index { |r, idx|
|
|
69
|
+
if r[2] == room
|
|
70
|
+
@box.currentItem = idx
|
|
71
|
+
break
|
|
72
|
+
end
|
|
73
|
+
}
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def initialize(map)
|
|
78
|
+
super(map.window.parent, BOX_LOCATIONS, DECOR_ALL, 40, 40, 420, 400)
|
|
79
|
+
|
|
80
|
+
@box = FXIconList.new(self, nil, 0,
|
|
81
|
+
ICONLIST_BROWSESELECT|
|
|
82
|
+
LAYOUT_FILL_X|LAYOUT_FILL_Y)
|
|
83
|
+
@box.appendHeader(BOX_NAME, nil, 120)
|
|
84
|
+
@box.appendHeader(BOX_SECTION, nil, 60)
|
|
85
|
+
@box.appendHeader(BOX_LOCATION, nil, 200)
|
|
86
|
+
@box.header.connect(SEL_COMMAND) { |sender, sel, which|
|
|
87
|
+
if @box.header.arrowUp?(which)
|
|
88
|
+
dir = MAYBE
|
|
89
|
+
elsif @box.header.arrowDown?(which)
|
|
90
|
+
dir = TRUE
|
|
91
|
+
else
|
|
92
|
+
dir = FALSE
|
|
93
|
+
end
|
|
94
|
+
0.upto(2) { |idx|
|
|
95
|
+
@box.header.setArrowDir(idx, MAYBE)
|
|
96
|
+
}
|
|
97
|
+
@box.header.setArrowDir(which, dir)
|
|
98
|
+
|
|
99
|
+
sort
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
@box.connect(SEL_COMMAND, method(:pick))
|
|
103
|
+
|
|
104
|
+
create
|
|
105
|
+
copy_from(map)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
end
|
data/lib/IFMapper/FXMap.rb
CHANGED
|
@@ -1,2116 +1,2147 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
require 'IFMapper/Map'
|
|
5
|
-
require 'IFMapper/FXSection'
|
|
6
|
-
require 'IFMapper/FXMapDialogBox'
|
|
7
|
-
require 'IFMapper/FXSectionDialogBox'
|
|
8
|
-
require 'IFMapper/AStar'
|
|
9
|
-
require '
|
|
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
|
-
@@
|
|
40
|
-
@@
|
|
41
|
-
@@
|
|
42
|
-
|
|
43
|
-
@@
|
|
44
|
-
@@
|
|
45
|
-
@@
|
|
46
|
-
@@
|
|
47
|
-
@@
|
|
48
|
-
@@
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
#
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
c.
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
#
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
#
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
#
|
|
367
|
-
#
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
#
|
|
388
|
-
#
|
|
389
|
-
#
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
#
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
#
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
end
|
|
493
|
-
if
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
title
|
|
553
|
-
@
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
#
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
@
|
|
573
|
-
@
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
@
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
@
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
#
|
|
613
|
-
quadrant =
|
|
614
|
-
|
|
615
|
-
#
|
|
616
|
-
quadrant =
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
#
|
|
625
|
-
quadrant =
|
|
626
|
-
|
|
627
|
-
#
|
|
628
|
-
quadrant =
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
x2 += WS
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
end
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
@complexConnection
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
end
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
#
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
#
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
end
|
|
900
|
-
|
|
901
|
-
#
|
|
902
|
-
#
|
|
903
|
-
#
|
|
904
|
-
def
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
end
|
|
1001
|
-
|
|
1002
|
-
#
|
|
1003
|
-
# Given
|
|
1004
|
-
#
|
|
1005
|
-
def
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
#
|
|
1040
|
-
#
|
|
1041
|
-
#
|
|
1042
|
-
def
|
|
1043
|
-
@sections[@section].rooms.
|
|
1044
|
-
@sections[@section].connections.
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
#
|
|
1049
|
-
#
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
cmd = FXMenuCommand.new(submenu, "
|
|
1065
|
-
cmd.connect(SEL_COMMAND) {
|
|
1066
|
-
room[
|
|
1067
|
-
room[
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
return
|
|
1134
|
-
end
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
#
|
|
1199
|
-
selection.
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
@
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
@
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
@
|
|
1343
|
-
@canvas.connect(
|
|
1344
|
-
|
|
1345
|
-
@canvas.connect(
|
|
1346
|
-
@canvas.
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
conns
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
#
|
|
1455
|
-
#
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
#
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
def
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
if @
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
when
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
when
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
when
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
end
|
|
2014
|
-
|
|
2015
|
-
#
|
|
2016
|
-
#
|
|
2017
|
-
#
|
|
2018
|
-
def
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
#
|
|
2038
|
-
#
|
|
2039
|
-
#
|
|
2040
|
-
def
|
|
2041
|
-
require 'IFMapper/
|
|
2042
|
-
file
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
end
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
require 'IFMapper/Map'
|
|
5
|
+
require 'IFMapper/FXSection'
|
|
6
|
+
require 'IFMapper/FXMapDialogBox'
|
|
7
|
+
require 'IFMapper/FXSectionDialogBox'
|
|
8
|
+
require 'IFMapper/AStar'
|
|
9
|
+
require 'IFMapper/FXWarningBox'
|
|
10
|
+
require 'thread'
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FXMap < Map
|
|
14
|
+
FILE_FORMAT_VERSION = 1 # Upgrade this if incompatible changes are made
|
|
15
|
+
# in the class so that file loading of old files
|
|
16
|
+
# can still be checked against.
|
|
17
|
+
|
|
18
|
+
attr_reader :zoom # Current zooming factor
|
|
19
|
+
attr_accessor :filename # Filename of current map (if any)
|
|
20
|
+
attr_reader :modified # Was map modified since being loaded?
|
|
21
|
+
attr_accessor :navigation # Map is navigation mode (no new nodes can be
|
|
22
|
+
# created)
|
|
23
|
+
attr_accessor :options # Map options
|
|
24
|
+
attr_reader :window # Fox Window for this map
|
|
25
|
+
attr :version # file format version
|
|
26
|
+
attr_reader :mutex # Mutex to avoid racing conditions while
|
|
27
|
+
# automapping
|
|
28
|
+
attr_reader :automap # automapping transcript
|
|
29
|
+
|
|
30
|
+
attr_reader :complexConnection
|
|
31
|
+
attr_reader :mouseButton
|
|
32
|
+
|
|
33
|
+
# pmap is a path map (a matrix or grid used for path finding).
|
|
34
|
+
# Rooms and paths are recorded there. Path finding is needed
|
|
35
|
+
# to draw complex connections (ie. those that are farther than one square)
|
|
36
|
+
# We now also use this for selecting of stuff, particularly complex paths.
|
|
37
|
+
attr :pmap
|
|
38
|
+
|
|
39
|
+
@@win = nil # Map Info window
|
|
40
|
+
@@roomlist = nil # Room List Window
|
|
41
|
+
@@itemlist = nil # Item List Window
|
|
42
|
+
|
|
43
|
+
@@tooltip = nil
|
|
44
|
+
@@cursor_arrow = nil
|
|
45
|
+
@@cursor_cross = nil
|
|
46
|
+
@@cursor_n = nil
|
|
47
|
+
@@cursor_ne = nil
|
|
48
|
+
@@cursor_e = nil
|
|
49
|
+
@@cursor_se = nil
|
|
50
|
+
@@cursor_s = nil
|
|
51
|
+
@@cursor_sw = nil
|
|
52
|
+
@@cursor_w = nil
|
|
53
|
+
@@cursor_nw = nil
|
|
54
|
+
|
|
55
|
+
#
|
|
56
|
+
# Map has changed dramatically. Update pathmap, title and redraw
|
|
57
|
+
#
|
|
58
|
+
def _changed
|
|
59
|
+
create_pathmap
|
|
60
|
+
if @window and @window.shown?
|
|
61
|
+
update_title
|
|
62
|
+
draw
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
#
|
|
68
|
+
# Jump to a certain section #
|
|
69
|
+
#
|
|
70
|
+
def section=(x)
|
|
71
|
+
clear_selection
|
|
72
|
+
super
|
|
73
|
+
@complexConnection = false
|
|
74
|
+
_changed
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
#
|
|
78
|
+
# Go to previous section (if any)
|
|
79
|
+
#
|
|
80
|
+
def previous_section
|
|
81
|
+
self.section = @section - 1
|
|
82
|
+
_changed
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#
|
|
86
|
+
# Go to next section (if any)
|
|
87
|
+
#
|
|
88
|
+
def next_section
|
|
89
|
+
self.section = @section + 1
|
|
90
|
+
_changed
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
#
|
|
94
|
+
# Map has been modified. Update also pathmap.
|
|
95
|
+
#
|
|
96
|
+
def modified=(x)
|
|
97
|
+
@modified = x
|
|
98
|
+
_changed
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
#
|
|
102
|
+
# Popup the section properties to allow renaming it
|
|
103
|
+
#
|
|
104
|
+
def rename_section
|
|
105
|
+
@sections[@section].properties(self)
|
|
106
|
+
modified = true
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
#
|
|
110
|
+
# Delete current section from map
|
|
111
|
+
#
|
|
112
|
+
def delete_section
|
|
113
|
+
return navigation_warning if @navigation
|
|
114
|
+
w = FXWarningBox.new(@window, WARN_DELETE_SECTION)
|
|
115
|
+
return if w.execute == 0
|
|
116
|
+
|
|
117
|
+
delete_section_at(@section)
|
|
118
|
+
modified = true
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
#
|
|
122
|
+
# Add a new section to map and make it current
|
|
123
|
+
#
|
|
124
|
+
def new_section
|
|
125
|
+
return navigation_warning if @navigation
|
|
126
|
+
@sections.push( FXSection.new )
|
|
127
|
+
@section = @sections.size - 1
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
#
|
|
131
|
+
# A simple debugging function that will spit out the path map with a
|
|
132
|
+
# very simple ascii representation.
|
|
133
|
+
#
|
|
134
|
+
def dump_pathmap
|
|
135
|
+
s = ' ' + ' ' * @width + "\n"
|
|
136
|
+
m = s * @height
|
|
137
|
+
(0...@width).each { |x|
|
|
138
|
+
(0...@height).each { |y|
|
|
139
|
+
m[y * (@width+2)] = (y % 10).to_s
|
|
140
|
+
loc = y * (@width+2) + x + 1
|
|
141
|
+
if @pmap.at(x).at(y).kind_of?(Connection)
|
|
142
|
+
m[loc] = '-'
|
|
143
|
+
elsif @pmap.at(x).at(y).kind_of?(Room)
|
|
144
|
+
m[loc] = 'R'
|
|
145
|
+
end
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
puts ' 0123456789' * (@width/10)
|
|
149
|
+
puts m
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
#
|
|
153
|
+
# Determine whether a pathmap area from x,y to x+w,y+h is free
|
|
154
|
+
# of rooms
|
|
155
|
+
#
|
|
156
|
+
def _free_area?(x, y, w, h)
|
|
157
|
+
x.upto(x+w) { |xx|
|
|
158
|
+
y.upto(x+h) { |yy|
|
|
159
|
+
return false if @pmap.at(xx).at(yy).kind_of?(Room)
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return true
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
#
|
|
166
|
+
# Return true or false if map is free at location x, y.
|
|
167
|
+
# If x and y coords are within pathmap, we use it.
|
|
168
|
+
# If not, we will use the brute force search of Map.rb
|
|
169
|
+
#
|
|
170
|
+
def free?(x, y)
|
|
171
|
+
if @pmap and x >= 0 and y >= 0 and @pmap.size > x and @pmap.at(x).size > y
|
|
172
|
+
return false if @pmap.at(x).at(y)
|
|
173
|
+
return true
|
|
174
|
+
else
|
|
175
|
+
super
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
#
|
|
180
|
+
# Given a list of rooms, find an area in the map where we could
|
|
181
|
+
# place them. If found, return x/y offset so rooms can be moved
|
|
182
|
+
# there. This is used for pasting rooms.
|
|
183
|
+
#
|
|
184
|
+
def find_empty_area(rooms)
|
|
185
|
+
return nil if rooms.empty?
|
|
186
|
+
minx = maxx = rooms[0].x
|
|
187
|
+
miny = maxy = rooms[0].y
|
|
188
|
+
rooms.each { |r|
|
|
189
|
+
minx = r.x if r.x < minx
|
|
190
|
+
maxx = r.x if r.x > maxx
|
|
191
|
+
miny = r.y if r.y < miny
|
|
192
|
+
maxy = r.y if r.y > maxy
|
|
193
|
+
}
|
|
194
|
+
w = maxx - minx
|
|
195
|
+
h = maxy - miny
|
|
196
|
+
|
|
197
|
+
# Find an area in pathmap that has w x h empty rooms
|
|
198
|
+
0.upto(@width-1-w) { |x|
|
|
199
|
+
0.upto(@height-1-h) { |y|
|
|
200
|
+
if _free_area?(x, y, w, h)
|
|
201
|
+
return [x - minx, y - miny]
|
|
202
|
+
end
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return nil
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
#
|
|
209
|
+
# Reinitialize the pathmap to an empty matrix
|
|
210
|
+
#
|
|
211
|
+
def empty_pathmap
|
|
212
|
+
# First, create an empty grid of width x height
|
|
213
|
+
@pmap = Array.new(@width)
|
|
214
|
+
(0...@width).each { |x|
|
|
215
|
+
@pmap[x] = Array.new(@height)
|
|
216
|
+
}
|
|
217
|
+
return pmap
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
#
|
|
221
|
+
# Recreate the pathmap based on rooms and connections
|
|
222
|
+
# This routine is used on loading a new map.
|
|
223
|
+
#
|
|
224
|
+
def create_pathmap
|
|
225
|
+
# First, create an empty grid of width x height
|
|
226
|
+
empty_pathmap
|
|
227
|
+
# Then, fill it in with all rooms...
|
|
228
|
+
@sections[@section].rooms.each { |r| @pmap[r.x][r.y] = r }
|
|
229
|
+
# And following, add all paths
|
|
230
|
+
@sections[@section].connections.each { |c| path_find(c) }
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
#
|
|
234
|
+
# Given a connection, clean its path from path map.
|
|
235
|
+
#
|
|
236
|
+
def clean_path(c)
|
|
237
|
+
c.gpts.each { |p| @pmap[p[0]][p[1]] = nil if @pmap[p[0]][p[1]] == c }
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
#
|
|
241
|
+
# Remove a connection from map, since path creation failed.
|
|
242
|
+
#
|
|
243
|
+
def remove_connection(c)
|
|
244
|
+
c.failed = true
|
|
245
|
+
status "#{ERR_PATH_FOR_CONNECTION} #{c} #{ERR_IS_BLOCKED}."
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Given a connection, create the path for it, if not a simple
|
|
249
|
+
# connection. Also, add the paths to pathmap.
|
|
250
|
+
def path_find(c)
|
|
251
|
+
unless c.complex?
|
|
252
|
+
c.pts = c.gpts = []
|
|
253
|
+
c.failed = false
|
|
254
|
+
return true
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Complex path... Generate points.
|
|
258
|
+
a, b = c.room
|
|
259
|
+
dirA, dirB = c.dirs
|
|
260
|
+
raise "A connection not found #{c} at #{a}" unless dirA
|
|
261
|
+
raise "B connection not found #{c} at #{b}" unless dirB
|
|
262
|
+
|
|
263
|
+
vA = FXRoom::DIR_TO_VECTOR[dirA]
|
|
264
|
+
vB = FXRoom::DIR_TO_VECTOR[dirB]
|
|
265
|
+
|
|
266
|
+
pA = [ a.x + vA[0], a.y + vA[1] ]
|
|
267
|
+
pB = [ b.x + vB[0], b.y + vB[1] ]
|
|
268
|
+
|
|
269
|
+
c.gpts = []
|
|
270
|
+
c.pts = []
|
|
271
|
+
|
|
272
|
+
# Check for the special case of looping path (path that begins and
|
|
273
|
+
# returns to same exit)
|
|
274
|
+
if a == b and dirA == dirB
|
|
275
|
+
pt = a.corner(c, 1, dirA)
|
|
276
|
+
n = 1.0 / Math.sqrt(vA[0] * vA[0] + vA[1] * vA[1])
|
|
277
|
+
vA = [ vA[0] * n, vA[1] * n ]
|
|
278
|
+
c.pts.push( [ pt[0], pt[1] ] )
|
|
279
|
+
pA = [ pt[0] + vA[0] * 20, pt[1] + vA[1] * 20 ]
|
|
280
|
+
c.pts.push( [pA[0], pA[1]] )
|
|
281
|
+
pB = [ pA[0] + vA[1] * 20, pA[1] - vA[0] * 20 ]
|
|
282
|
+
c.pts.push( [pB[0], pB[1]] )
|
|
283
|
+
pC = [ pB[0] - vA[0] * 20, pB[1] - vA[1] * 20 ]
|
|
284
|
+
c.pts.push( [pC[0], pC[1]] )
|
|
285
|
+
c.dir = Connection::AtoB
|
|
286
|
+
return true
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Now check if start or goal are fully blocked. If so,
|
|
290
|
+
# fail quickly
|
|
291
|
+
if pA[0] < 0 or pA[0] >= @width or
|
|
292
|
+
pB[0] < 0 or pB[0] >= @width or
|
|
293
|
+
pA[1] < 0 or pA[1] >= @height or
|
|
294
|
+
pB[1] < 0 or pB[1] >= @height or
|
|
295
|
+
@pmap.at(pA[0]).at(pA[1]).kind_of?(Room) or
|
|
296
|
+
@pmap.at(pB[0]).at(pB[1]).kind_of?(Room)
|
|
297
|
+
remove_connection(c)
|
|
298
|
+
return false
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
if (pA[0] - pB[0]).abs > 30 or
|
|
302
|
+
(pA[1] - pB[1]).abs > 30
|
|
303
|
+
c.failed = true
|
|
304
|
+
return
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
# No, okay, we need to do true A* path finding
|
|
308
|
+
c.failed = false
|
|
309
|
+
aStar = AStar.new
|
|
310
|
+
MapNode::map(@pmap)
|
|
311
|
+
start = MapNode.new( pA[0], pA[1] )
|
|
312
|
+
goal = MapNode.new( pB[0], pB[1] )
|
|
313
|
+
aStar.goals( start, goal )
|
|
314
|
+
while aStar.search_step == AStar::SEARCH_STATE_SEARCHING
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
# Oops, AStar failed. Not a clean path
|
|
318
|
+
if aStar.state == AStar::SEARCH_STATE_FAILED
|
|
319
|
+
remove_connection(c)
|
|
320
|
+
return false
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
# We succeeded. Get the path
|
|
324
|
+
c.failed = false
|
|
325
|
+
c.gpts = aStar.path
|
|
326
|
+
# Put path in pathmap so subsequent paths will try to avoid crossing it.
|
|
327
|
+
c.gpts.each { |p| @pmap[p[0]][p[1]] = c }
|
|
328
|
+
|
|
329
|
+
# Okay, we have a valid path.
|
|
330
|
+
# Create real path in display coordinates now...
|
|
331
|
+
# Start with a's corner
|
|
332
|
+
pt = a.corner(c, 1, dirA)
|
|
333
|
+
c.pts.push( [ pt[0], pt[1] ] )
|
|
334
|
+
# Then, add each grid point we calculated
|
|
335
|
+
c.gpts.each { |pt|
|
|
336
|
+
x = pt[0] * WW + WW / 2
|
|
337
|
+
y = pt[1] * HH + HH / 2
|
|
338
|
+
c.pts.push([x, y])
|
|
339
|
+
}
|
|
340
|
+
# And end with b's corner
|
|
341
|
+
pt = b.corner(c, 1, dirB)
|
|
342
|
+
return c.pts.push([pt[0], pt[1]])
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
#
|
|
346
|
+
# Add a new path point to a connection
|
|
347
|
+
#
|
|
348
|
+
def add_path_pt( c, x, y )
|
|
349
|
+
@pmap[x][y] = c
|
|
350
|
+
c.gpts.push([x, y])
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
#
|
|
354
|
+
# Used for loading class with Marshal
|
|
355
|
+
#
|
|
356
|
+
def marshal_load(variables)
|
|
357
|
+
@zoom = variables.shift
|
|
358
|
+
@navigation = variables.shift
|
|
359
|
+
@options = variables.shift
|
|
360
|
+
super
|
|
361
|
+
@modified = false
|
|
362
|
+
@complexConnection = nil
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
#
|
|
366
|
+
# Used for saving class with Marshal
|
|
367
|
+
#
|
|
368
|
+
def marshal_dump
|
|
369
|
+
[ @zoom, @navigation, @options ] + super
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
#
|
|
373
|
+
# Used to copy relevant data from one (temporary) map to another
|
|
374
|
+
#
|
|
375
|
+
def copy(b)
|
|
376
|
+
super(b)
|
|
377
|
+
if b.kind_of?(FXMap)
|
|
378
|
+
@options = b.options if b.options
|
|
379
|
+
@filename = b.filename
|
|
380
|
+
self.zoom = b.zoom
|
|
381
|
+
@navigation = b.navigation
|
|
382
|
+
@modified = true
|
|
383
|
+
@complexConnection = nil
|
|
384
|
+
end
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
#
|
|
388
|
+
# Create a new room for the current section
|
|
389
|
+
#
|
|
390
|
+
def new_room(x, y)
|
|
391
|
+
@modified = true
|
|
392
|
+
r = @sections[@section].new_room(x, y)
|
|
393
|
+
return r
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
#
|
|
397
|
+
# Function used to add a new room. x and y are absolute pixel positions
|
|
398
|
+
# in canvas.
|
|
399
|
+
#
|
|
400
|
+
def new_xy_room(x, y)
|
|
401
|
+
x = x / WW
|
|
402
|
+
y = y / HH
|
|
403
|
+
r = new_room(x, y)
|
|
404
|
+
@pmap[x][y] = r
|
|
405
|
+
|
|
406
|
+
r.selected = true
|
|
407
|
+
|
|
408
|
+
if @options['Edit on Creation']
|
|
409
|
+
if not r.modal_properties(self)
|
|
410
|
+
@sections[@section].delete_room(r)
|
|
411
|
+
@pmap[x][y] = nil
|
|
412
|
+
return nil
|
|
413
|
+
end
|
|
414
|
+
end
|
|
415
|
+
update_roomlist
|
|
416
|
+
return r
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
#
|
|
420
|
+
# Given a room, delete it
|
|
421
|
+
#
|
|
422
|
+
def delete_room_only(r)
|
|
423
|
+
if @pmap and r.x < @pmap.size and r.y < @pmap.size and
|
|
424
|
+
r.x >= 0 and r.y >= 0
|
|
425
|
+
@pmap[r.x][r.y] = nil
|
|
426
|
+
end
|
|
427
|
+
super
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
#
|
|
431
|
+
# Given a room, delete it
|
|
432
|
+
#
|
|
433
|
+
def delete_room(r)
|
|
434
|
+
if @pmap and r.x < @pmap.size and r.y < @pmap.size and
|
|
435
|
+
r.x >= 0 and r.y >= 0
|
|
436
|
+
@pmap[r.x][r.y] = nil
|
|
437
|
+
end
|
|
438
|
+
super
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Given a canvas (mouse) x/y position, return:
|
|
442
|
+
#
|
|
443
|
+
# false - arrow click
|
|
444
|
+
# true - room click
|
|
445
|
+
#
|
|
446
|
+
def click_type(x, y)
|
|
447
|
+
x = (x % WW).to_i
|
|
448
|
+
y = (y % HH).to_i
|
|
449
|
+
|
|
450
|
+
if x >= WS_2 and y >= HS_2 and
|
|
451
|
+
x <= (W + WS_2) and y <= (H + HS_2)
|
|
452
|
+
return true
|
|
453
|
+
else
|
|
454
|
+
return false
|
|
455
|
+
end
|
|
456
|
+
end
|
|
457
|
+
|
|
458
|
+
# Given an x and y canvas position, return room object,
|
|
459
|
+
# complex connection or nil
|
|
460
|
+
def to_room(x,y)
|
|
461
|
+
xx = x / WW
|
|
462
|
+
yy = y / HH
|
|
463
|
+
return @pmap.at(xx).at(yy)
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
# Given a mouse click x/y position, return object(s) if any or nil
|
|
467
|
+
def to_object(x, y)
|
|
468
|
+
|
|
469
|
+
exitA = get_quadrant(x, y)
|
|
470
|
+
unless exitA
|
|
471
|
+
# Not in arrow section, return element based on pmap
|
|
472
|
+
# can be a room or complex arrow connection.
|
|
473
|
+
xx = x / WW
|
|
474
|
+
yy = y / HH
|
|
475
|
+
return nil if xx >= @width or yy >= @height
|
|
476
|
+
return @pmap.at(xx).at(yy)
|
|
477
|
+
else
|
|
478
|
+
# Possible arrow
|
|
479
|
+
@sections[@section].connections.each { |c|
|
|
480
|
+
a = c.roomA
|
|
481
|
+
b = c.roomB
|
|
482
|
+
next if not b and @complexConnection
|
|
483
|
+
|
|
484
|
+
if c.gpts.size > 0
|
|
485
|
+
2.times { |t|
|
|
486
|
+
if t == 0
|
|
487
|
+
r = a
|
|
488
|
+
dir = r.exits.index(c)
|
|
489
|
+
else
|
|
490
|
+
r = b
|
|
491
|
+
dir = r.exits.rindex(c)
|
|
492
|
+
end
|
|
493
|
+
next if not r
|
|
494
|
+
x1, y1 = r.corner(c, 1, dir)
|
|
495
|
+
v = FXRoom::DIR_TO_VECTOR[dir]
|
|
496
|
+
x2 = x1 + v[0] * WS
|
|
497
|
+
y2 = y1 + v[1] * HS
|
|
498
|
+
if x1 == x2
|
|
499
|
+
x1 -= W / 2
|
|
500
|
+
x2 += W / 2
|
|
501
|
+
end
|
|
502
|
+
if y1 == y2
|
|
503
|
+
y1 -= H / 2
|
|
504
|
+
y2 += H / 2
|
|
505
|
+
end
|
|
506
|
+
x1, x2 = x2, x1 if x2 < x1
|
|
507
|
+
y1, y2 = y2, y1 if y2 < y1
|
|
508
|
+
|
|
509
|
+
if x >= x1 and x <= x2 and
|
|
510
|
+
y >= y1 and y < y2
|
|
511
|
+
return c
|
|
512
|
+
end
|
|
513
|
+
}
|
|
514
|
+
else
|
|
515
|
+
x1, y1 = a.corner(c, 1, a.exits.index(c))
|
|
516
|
+
if b
|
|
517
|
+
x2, y2 = b.corner(c, 1, b.exits.rindex(c))
|
|
518
|
+
else
|
|
519
|
+
dir = a.exits.index(c)
|
|
520
|
+
v = FXRoom::DIR_TO_VECTOR[dir]
|
|
521
|
+
x2 = x1 + v[0] * WS
|
|
522
|
+
y2 = y1 + v[1] * HS
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
x1, x2 = x2, x1 if x2 < x1
|
|
526
|
+
y1, y2 = y2, y1 if y2 < y1
|
|
527
|
+
if x1 == x2
|
|
528
|
+
x1 -= W / 2
|
|
529
|
+
x2 += W / 2
|
|
530
|
+
end
|
|
531
|
+
if y1 == y2
|
|
532
|
+
y1 -= H / 2
|
|
533
|
+
y2 += H / 2
|
|
534
|
+
end
|
|
535
|
+
if x >= x1 and x <= x2 and
|
|
536
|
+
y >= y1 and y < y2
|
|
537
|
+
return c
|
|
538
|
+
end
|
|
539
|
+
end
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return nil
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
return nil
|
|
546
|
+
end
|
|
547
|
+
|
|
548
|
+
#
|
|
549
|
+
# Update the map window's title
|
|
550
|
+
#
|
|
551
|
+
def update_title
|
|
552
|
+
title = @name.dup
|
|
553
|
+
if @navigation
|
|
554
|
+
title << " #{TITLE_READ_ONLY}"
|
|
555
|
+
end
|
|
556
|
+
if @automap
|
|
557
|
+
title << " #{TITLE_AUTOMAP}"
|
|
558
|
+
end
|
|
559
|
+
title << " #{TITLE_ZOOM} %.3f" % @zoom
|
|
560
|
+
title << " #{TITLE_SECTION} #{@section+1} #{TITLE_OF} #{@sections.size}"
|
|
561
|
+
title << " #{@sections[@section].name}"
|
|
562
|
+
@window.title = title
|
|
563
|
+
end
|
|
564
|
+
|
|
565
|
+
# Change zoom factor of map. Rebuild fonts and canvas sizes.
|
|
566
|
+
def zoom=(value)
|
|
567
|
+
@zoom = ("%.2f" % value).to_f
|
|
568
|
+
# Create the font
|
|
569
|
+
fontsize = (11 * @zoom).to_i
|
|
570
|
+
|
|
571
|
+
if @window
|
|
572
|
+
@font = FXFont.new(@window.getApp, @options['Font Text'], fontsize)
|
|
573
|
+
@font.create
|
|
574
|
+
|
|
575
|
+
@objfont = FXFont.new(@window.getApp, @options['Font Objects'],
|
|
576
|
+
(fontsize * 0.75).to_i)
|
|
577
|
+
@objfont.create
|
|
578
|
+
|
|
579
|
+
width = (WW * @width * @zoom).to_i
|
|
580
|
+
height = (HH * @height * @zoom).to_i
|
|
581
|
+
@canvas.width = width
|
|
582
|
+
@canvas.height = height
|
|
583
|
+
|
|
584
|
+
# Then, create an off-screen image with that same size for double
|
|
585
|
+
# buffering
|
|
586
|
+
@image.release
|
|
587
|
+
@image.destroy
|
|
588
|
+
GC.start
|
|
589
|
+
|
|
590
|
+
@image = FXBMPImage.new(@window.getApp, nil, IMAGE_SHMI|IMAGE_SHMP,
|
|
591
|
+
width, height)
|
|
592
|
+
@image.create
|
|
593
|
+
update_title
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
end
|
|
597
|
+
|
|
598
|
+
# Given a mouse x/y position to WS/HS, return an index
|
|
599
|
+
# indicating what quadrant it belongs to.
|
|
600
|
+
def get_quadrant(ax, ay)
|
|
601
|
+
# First get relative x/y position
|
|
602
|
+
x = ax % WW
|
|
603
|
+
y = ay % HH
|
|
604
|
+
|
|
605
|
+
quadrant = nil
|
|
606
|
+
if x < WS_2
|
|
607
|
+
#left
|
|
608
|
+
if y < HS_2
|
|
609
|
+
# top
|
|
610
|
+
quadrant = 7
|
|
611
|
+
elsif y > H + HS_2
|
|
612
|
+
# bottom
|
|
613
|
+
quadrant = 5
|
|
614
|
+
else
|
|
615
|
+
# center
|
|
616
|
+
quadrant = 6
|
|
617
|
+
end
|
|
618
|
+
elsif x > W + WS_2
|
|
619
|
+
# right
|
|
620
|
+
if y < HS_2
|
|
621
|
+
# top
|
|
622
|
+
quadrant = 1
|
|
623
|
+
elsif y > H + HS_2
|
|
624
|
+
# bottom
|
|
625
|
+
quadrant = 3
|
|
626
|
+
else
|
|
627
|
+
# center
|
|
628
|
+
quadrant = 2
|
|
629
|
+
end
|
|
630
|
+
else
|
|
631
|
+
#center
|
|
632
|
+
if y < HS_2
|
|
633
|
+
# top
|
|
634
|
+
quadrant = 0
|
|
635
|
+
elsif y > H + HS_2
|
|
636
|
+
# bottom
|
|
637
|
+
quadrant = 4
|
|
638
|
+
else
|
|
639
|
+
# center
|
|
640
|
+
quadrant = nil
|
|
641
|
+
end
|
|
642
|
+
end
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
return quadrant
|
|
646
|
+
end
|
|
647
|
+
|
|
648
|
+
# Given an x,y absolute position corresponding to a connection,
|
|
649
|
+
# return connected rooms (if any).
|
|
650
|
+
def quadrant_to_rooms( q, x, y )
|
|
651
|
+
maxX = @width * WW
|
|
652
|
+
maxY = @height * HH
|
|
653
|
+
|
|
654
|
+
# First check if user tried adding a connection
|
|
655
|
+
# at the edges of the map. If so, return empty stuff.
|
|
656
|
+
if x < WS_2 or y < HS_2 or
|
|
657
|
+
x > maxX - WS_2 or y > maxY - HS_2
|
|
658
|
+
return [nil, nil, nil, nil]
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
x1 = x2 = x
|
|
662
|
+
y1 = y2 = y
|
|
663
|
+
|
|
664
|
+
case q
|
|
665
|
+
when 0, 4
|
|
666
|
+
y1 -= HS
|
|
667
|
+
y2 += HS
|
|
668
|
+
when 1, 5
|
|
669
|
+
x1 -= WS
|
|
670
|
+
x2 += WS
|
|
671
|
+
y1 += HS
|
|
672
|
+
y2 -= HS
|
|
673
|
+
when 2, 6
|
|
674
|
+
x1 -= WS
|
|
675
|
+
x2 += WS
|
|
676
|
+
when 3, 7
|
|
677
|
+
x1 -= WS
|
|
678
|
+
y1 -= HS
|
|
679
|
+
x2 += WS
|
|
680
|
+
y2 += HS
|
|
681
|
+
end
|
|
682
|
+
|
|
683
|
+
case q
|
|
684
|
+
when 0, 5, 6, 7
|
|
685
|
+
x1, x2 = x2, x1
|
|
686
|
+
y1, y2 = y2, y1
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
roomA = to_room(x1, y1)
|
|
690
|
+
roomB = to_room(x2, y2)
|
|
691
|
+
# Oops, user tried to create rooms where we already
|
|
692
|
+
# have a complex connection. Don't create anything, then.
|
|
693
|
+
if roomA.kind_of?(Connection) or
|
|
694
|
+
(roomB.kind_of?(Connection) and not @complexConnection)
|
|
695
|
+
return [roomA, roomB, nil, nil]
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
return [roomA, roomB, [x1, y1], [x2, y2]]
|
|
699
|
+
end
|
|
700
|
+
|
|
701
|
+
#
|
|
702
|
+
# Add a new complex connection (or its first point)
|
|
703
|
+
#
|
|
704
|
+
def new_complex_connection( x, y )
|
|
705
|
+
exitA = get_quadrant(x, y)
|
|
706
|
+
unless exitA
|
|
707
|
+
raise "not a connection"
|
|
708
|
+
end
|
|
709
|
+
roomA, roomB, a, b = quadrant_to_rooms( exitA, x, y )
|
|
710
|
+
unless a and roomA and roomA[exitA] == nil
|
|
711
|
+
return
|
|
712
|
+
end
|
|
713
|
+
_new_complex_connection(roomA, exitA)
|
|
714
|
+
end
|
|
715
|
+
|
|
716
|
+
def _new_complex_connection(roomA, exitA)
|
|
717
|
+
if @complexConnection.kind_of?(TrueClass)
|
|
718
|
+
@complexConnection = [roomA, exitA]
|
|
719
|
+
c = new_connection( roomA, exitA, nil )
|
|
720
|
+
status MSG_COMPLEX_CONNECTION_OTHER_EXIT
|
|
721
|
+
else
|
|
722
|
+
@sections[@section].delete_connection_at(-1)
|
|
723
|
+
c = new_connection( @complexConnection[0],
|
|
724
|
+
@complexConnection[1], roomA, exitA )
|
|
725
|
+
if path_find(c) # Do A* path finding to connect both exits
|
|
726
|
+
@modified = true
|
|
727
|
+
status MSG_COMPLEX_CONNECTION_DONE
|
|
728
|
+
else
|
|
729
|
+
@sections[@section].delete_connection_at(-1)
|
|
730
|
+
end
|
|
731
|
+
draw
|
|
732
|
+
@complexConnection = nil
|
|
733
|
+
end
|
|
734
|
+
end
|
|
735
|
+
|
|
736
|
+
#
|
|
737
|
+
# Add a new room connection among contiguous rooms.
|
|
738
|
+
#
|
|
739
|
+
def new_xy_connection( x, y )
|
|
740
|
+
exitA = get_quadrant(x, y)
|
|
741
|
+
unless exitA
|
|
742
|
+
raise "not a connection"
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
# Then, get rooms being connected
|
|
746
|
+
roomA, roomB, a, b = quadrant_to_rooms( exitA, x, y )
|
|
747
|
+
return unless a # User click outside map
|
|
748
|
+
|
|
749
|
+
if @options['Create on Connection']
|
|
750
|
+
roomA = new_xy_room( a[0], a[1] ) unless roomA
|
|
751
|
+
roomB = new_xy_room( b[0], b[1] ) unless roomB
|
|
752
|
+
end
|
|
753
|
+
|
|
754
|
+
return nil unless roomA and roomB
|
|
755
|
+
|
|
756
|
+
if roomA == roomB
|
|
757
|
+
raise "error: same room connection"
|
|
758
|
+
end
|
|
759
|
+
|
|
760
|
+
@modified = true
|
|
761
|
+
if roomA and exitA
|
|
762
|
+
# get old connection
|
|
763
|
+
if roomA[exitA]
|
|
764
|
+
c = roomA[exitA]
|
|
765
|
+
delete_connection(c) if c.roomB == nil
|
|
766
|
+
end
|
|
767
|
+
exitB = (exitA + 4) % 8
|
|
768
|
+
if roomB[exitB]
|
|
769
|
+
c = roomB[exitB]
|
|
770
|
+
delete_connection(c) if c.roomB == nil
|
|
771
|
+
end
|
|
772
|
+
end
|
|
773
|
+
begin
|
|
774
|
+
new_connection( roomA, exitA, roomB )
|
|
775
|
+
rescue Section::ConnectionError
|
|
776
|
+
end
|
|
777
|
+
end
|
|
778
|
+
|
|
779
|
+
#
|
|
780
|
+
# Handle mouse button double clicks in canvas
|
|
781
|
+
#
|
|
782
|
+
def double_click_cb(selection, event)
|
|
783
|
+
return unless selection
|
|
784
|
+
if selection.kind_of?(FXRoom) or selection.kind_of?(FXConnection)
|
|
785
|
+
selection.properties( self, event )
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
|
|
789
|
+
# Self-explanatory.
|
|
790
|
+
def zoom_out
|
|
791
|
+
if @zoom > 0.1
|
|
792
|
+
self.zoom -= 0.1
|
|
793
|
+
end
|
|
794
|
+
end
|
|
795
|
+
|
|
796
|
+
# Self-explanatory.
|
|
797
|
+
def zoom_in
|
|
798
|
+
if @zoom < 1.25
|
|
799
|
+
self.zoom += 0.1
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
# Spit out a new message to the status line.
|
|
804
|
+
def status(msg)
|
|
805
|
+
mw = @window.parent.parent
|
|
806
|
+
statusbar = mw.children.find() { |x| x.kind_of?(FXStatusBar) }
|
|
807
|
+
s = statusbar.statusLine
|
|
808
|
+
s.normalText = s.text = msg
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
#
|
|
812
|
+
# Based on x,y coordinate, switch mouse icon shape
|
|
813
|
+
#
|
|
814
|
+
def cursor_switch(x, y)
|
|
815
|
+
if not @options['Use Room Cursor']
|
|
816
|
+
@canvas.defaultCursor = @@cursor_arrow
|
|
817
|
+
return
|
|
818
|
+
end
|
|
819
|
+
q = get_quadrant(x, y)
|
|
820
|
+
case q
|
|
821
|
+
when 0
|
|
822
|
+
@canvas.defaultCursor = @@cursor_n
|
|
823
|
+
when 1
|
|
824
|
+
@canvas.defaultCursor = @@cursor_ne
|
|
825
|
+
when 2
|
|
826
|
+
@canvas.defaultCursor = @@cursor_e
|
|
827
|
+
when 3
|
|
828
|
+
@canvas.defaultCursor = @@cursor_se
|
|
829
|
+
when 4
|
|
830
|
+
@canvas.defaultCursor = @@cursor_s
|
|
831
|
+
when 5
|
|
832
|
+
@canvas.defaultCursor = @@cursor_sw
|
|
833
|
+
when 6
|
|
834
|
+
@canvas.defaultCursor = @@cursor_w
|
|
835
|
+
when 7
|
|
836
|
+
@canvas.defaultCursor = @@cursor_nw
|
|
837
|
+
else
|
|
838
|
+
@canvas.defaultCursor = @@cursor_arrow
|
|
839
|
+
end
|
|
840
|
+
end
|
|
841
|
+
|
|
842
|
+
#
|
|
843
|
+
# Based on mouse position on canvas, create a tooltip
|
|
844
|
+
#
|
|
845
|
+
def tooltip_cb(sender, id, ptr)
|
|
846
|
+
if @zoom < 0.6 and @tooltip_msg != ''
|
|
847
|
+
sender.text = @tooltip_msg.to_s
|
|
848
|
+
sender.show
|
|
849
|
+
else
|
|
850
|
+
sender.hide
|
|
851
|
+
end
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
#
|
|
856
|
+
# Show some help status in status line based on cursor position
|
|
857
|
+
#
|
|
858
|
+
def help_cb(sender, sel, event)
|
|
859
|
+
|
|
860
|
+
x = (event.last_x / @zoom).to_i
|
|
861
|
+
y = (event.last_y / @zoom).to_i
|
|
862
|
+
if @complexConnection
|
|
863
|
+
cursor_switch(x,y)
|
|
864
|
+
return
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
@tooltip_msg = ''
|
|
868
|
+
sel = to_object(x, y)
|
|
869
|
+
if sel
|
|
870
|
+
@canvas.defaultCursor = @@cursor_arrow
|
|
871
|
+
if sel.kind_of?(Room)
|
|
872
|
+
@tooltip_msg = sel.name
|
|
873
|
+
status "\"#{sel.name}\": #{MSG_CLICK_TO_SELECT_AND_MOVE}"
|
|
874
|
+
elsif sel.kind_of?(Connection)
|
|
875
|
+
status MSG_CLICK_CHANGE_DIR
|
|
876
|
+
end
|
|
877
|
+
else
|
|
878
|
+
if click_type(x, y)
|
|
879
|
+
@canvas.defaultCursor = @@cursor_cross
|
|
880
|
+
status MSG_CLICK_CREATE_ROOM
|
|
881
|
+
else
|
|
882
|
+
cursor_switch(x, y)
|
|
883
|
+
status MSG_CLICK_CREATE_LINK
|
|
884
|
+
end
|
|
885
|
+
end
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
#
|
|
889
|
+
# zoom in/out based on mousewheel, keeping position relative
|
|
890
|
+
# to cursor position
|
|
891
|
+
#
|
|
892
|
+
def mousewheel_cb(sender, sel, event)
|
|
893
|
+
case event.code
|
|
894
|
+
when -120 # Hmm, there does not seem to be constants for these
|
|
895
|
+
zoom_out
|
|
896
|
+
when 120 # Hmm, there does not seem to be constants for these
|
|
897
|
+
zoom_in
|
|
898
|
+
end
|
|
899
|
+
end
|
|
900
|
+
|
|
901
|
+
#
|
|
902
|
+
# Handle middle mouse button click in canvas
|
|
903
|
+
#
|
|
904
|
+
def mmb_click_cb(server, sel, event)
|
|
905
|
+
@canvas.grab
|
|
906
|
+
@dx = @dy = 0
|
|
907
|
+
@mouseButton = MIDDLEBUTTON
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
#
|
|
911
|
+
# Select all rooms and connections within (drag) rectangle
|
|
912
|
+
#
|
|
913
|
+
def select_rectangle(x1, y1, x2, y2)
|
|
914
|
+
x1, x2 = x2, x1 if x2 < x1
|
|
915
|
+
y1, y2 = y2, y1 if y2 < y1
|
|
916
|
+
|
|
917
|
+
x = x1 * zoom
|
|
918
|
+
y = y1 * zoom
|
|
919
|
+
w = x2 - x1
|
|
920
|
+
h = y2 - y1
|
|
921
|
+
|
|
922
|
+
x1 = ((x1 - WS_2) / WW).floor
|
|
923
|
+
y1 = ((y1 - HS_2) / HH).floor
|
|
924
|
+
x2 = ((x2 - WS_2) / WW).ceil
|
|
925
|
+
y2 = ((y2 - HS_2) / HH).ceil
|
|
926
|
+
|
|
927
|
+
@sections[@section].rooms.each { |r|
|
|
928
|
+
if r.x >= x1 and r.x <= x2 and
|
|
929
|
+
r.y >= y1 and r.y <= y2
|
|
930
|
+
r.selected = true
|
|
931
|
+
r.update_properties(self)
|
|
932
|
+
else
|
|
933
|
+
r.selected = false
|
|
934
|
+
end
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
@sections[@section].connections.each { |c|
|
|
938
|
+
next if not c.roomB
|
|
939
|
+
a = c.roomA
|
|
940
|
+
b = c.roomB
|
|
941
|
+
|
|
942
|
+
if (a.x >= x1 and a.x <= x2 and
|
|
943
|
+
a.y >= y1 and a.y <= y2) or
|
|
944
|
+
(b.x >= x1 and b.x <= x2 and
|
|
945
|
+
b.y >= y1 and b.y <= y2)
|
|
946
|
+
c.selected = true
|
|
947
|
+
c.update_properties(self)
|
|
948
|
+
else
|
|
949
|
+
c.selected = false
|
|
950
|
+
end
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
draw
|
|
954
|
+
dc = FXDCWindow.new(@canvas)
|
|
955
|
+
dc.function = BLT_NOT_SRC_XOR_DST
|
|
956
|
+
dc.drawRectangle(x, y, w * @zoom, h * @zoom)
|
|
957
|
+
dc.end
|
|
958
|
+
end
|
|
959
|
+
|
|
960
|
+
#
|
|
961
|
+
# Handle mouse motion in canvas
|
|
962
|
+
#
|
|
963
|
+
def motion_cb(server, sel, event)
|
|
964
|
+
if @mouseButton == MIDDLEBUTTON
|
|
965
|
+
@canvas.dragCursor = @@cursor_move
|
|
966
|
+
pos = @scrollwindow.position
|
|
967
|
+
dx = event.last_x - event.win_x
|
|
968
|
+
dy = event.last_y - event.win_y
|
|
969
|
+
if dx != 0 or dy != 0 and not (dx == @dx and dy == @dy)
|
|
970
|
+
pos[0] += dx
|
|
971
|
+
pos[1] += dy
|
|
972
|
+
@dx = dx
|
|
973
|
+
@dy = dy
|
|
974
|
+
@scrollwindow.setPosition(pos[0], pos[1])
|
|
975
|
+
@canvas.repaint
|
|
976
|
+
end
|
|
977
|
+
elsif @mouseButton == LEFTBUTTON
|
|
978
|
+
x = (event.last_x / @zoom).to_i
|
|
979
|
+
y = (event.last_y / @zoom).to_i
|
|
980
|
+
select_rectangle( @dx, @dy, x, y )
|
|
981
|
+
else
|
|
982
|
+
help_cb(server, sel, event)
|
|
983
|
+
end
|
|
984
|
+
end
|
|
985
|
+
|
|
986
|
+
#
|
|
987
|
+
# Handle release of middle mouse button
|
|
988
|
+
#
|
|
989
|
+
def mmb_release_cb(server, sel, event)
|
|
990
|
+
if @mouseButton
|
|
991
|
+
@canvas.ungrab
|
|
992
|
+
@canvas.dragCursor = @@cursor_arrow
|
|
993
|
+
if @mouseButton == LEFTBUTTON
|
|
994
|
+
draw
|
|
995
|
+
else
|
|
996
|
+
@canvas.repaint
|
|
997
|
+
end
|
|
998
|
+
@mouseButton = nil
|
|
999
|
+
end
|
|
1000
|
+
end
|
|
1001
|
+
|
|
1002
|
+
#
|
|
1003
|
+
# Given a room, center scrollwindow so room is visible
|
|
1004
|
+
#
|
|
1005
|
+
def center_view_on_room(r)
|
|
1006
|
+
xx = (r.xx + W / 2) * @zoom
|
|
1007
|
+
yy = (r.yy + H / 2) * @zoom
|
|
1008
|
+
center_view_on_xy(xx, yy)
|
|
1009
|
+
end
|
|
1010
|
+
|
|
1011
|
+
#
|
|
1012
|
+
# Given an x and y coordinate for the canvas, center on it
|
|
1013
|
+
#
|
|
1014
|
+
def center_view_on_xy(xx, yy)
|
|
1015
|
+
cw = @scrollwindow.getContentWidth
|
|
1016
|
+
ch = @scrollwindow.getContentHeight
|
|
1017
|
+
w = @scrollwindow.getViewportWidth
|
|
1018
|
+
h = @scrollwindow.getViewportHeight
|
|
1019
|
+
|
|
1020
|
+
xx -= w / 2
|
|
1021
|
+
yy -= h / 2
|
|
1022
|
+
maxx = cw - w / 2
|
|
1023
|
+
maxy = ch - h / 2
|
|
1024
|
+
if xx > maxx
|
|
1025
|
+
xx = maxx
|
|
1026
|
+
elsif xx < 0
|
|
1027
|
+
xx = 0
|
|
1028
|
+
end
|
|
1029
|
+
if yy > maxy
|
|
1030
|
+
yy = maxy
|
|
1031
|
+
elsif yy < 0
|
|
1032
|
+
yy = 0
|
|
1033
|
+
end
|
|
1034
|
+
|
|
1035
|
+
@scrollwindow.setPosition( -xx, -yy )
|
|
1036
|
+
end
|
|
1037
|
+
|
|
1038
|
+
#
|
|
1039
|
+
# Return current selection as an array of rooms and an array of
|
|
1040
|
+
# connections
|
|
1041
|
+
#
|
|
1042
|
+
def get_selection
|
|
1043
|
+
rooms = @sections[@section].rooms.find_all { |r| r.selected }
|
|
1044
|
+
conns = @sections[@section].connections.find_all { |r| r.selected }
|
|
1045
|
+
return rooms, conns
|
|
1046
|
+
end
|
|
1047
|
+
|
|
1048
|
+
#
|
|
1049
|
+
# Clear rooms/connections selected
|
|
1050
|
+
#
|
|
1051
|
+
def clear_selection
|
|
1052
|
+
@sections[@section].rooms.each { |r| r.selected = false }
|
|
1053
|
+
@sections[@section].connections.each { |r| r.selected = false }
|
|
1054
|
+
end
|
|
1055
|
+
|
|
1056
|
+
#
|
|
1057
|
+
# Add a proper link submenu option for an exit
|
|
1058
|
+
#
|
|
1059
|
+
def rmb_link_menu(submenu, c, room, idx, old_idx)
|
|
1060
|
+
return if room[idx] == c
|
|
1061
|
+
dir = Room::DIRECTIONS[idx]
|
|
1062
|
+
dir = dir.upcase
|
|
1063
|
+
if room[idx]
|
|
1064
|
+
cmd = FXMenuCommand.new(submenu, "Switch with link in #{dir} Exit")
|
|
1065
|
+
cmd.connect(SEL_COMMAND) {
|
|
1066
|
+
c2 = room[idx]
|
|
1067
|
+
room[old_idx] = c2
|
|
1068
|
+
room[idx] = c
|
|
1069
|
+
create_pathmap
|
|
1070
|
+
draw
|
|
1071
|
+
}
|
|
1072
|
+
else
|
|
1073
|
+
cmd = FXMenuCommand.new(submenu, "Move link to #{dir} Exit")
|
|
1074
|
+
cmd.connect(SEL_COMMAND) {
|
|
1075
|
+
room[old_idx] = nil
|
|
1076
|
+
room[idx] = c
|
|
1077
|
+
create_pathmap
|
|
1078
|
+
draw
|
|
1079
|
+
}
|
|
1080
|
+
end
|
|
1081
|
+
end
|
|
1082
|
+
|
|
1083
|
+
#
|
|
1084
|
+
# Handle right mouse button click
|
|
1085
|
+
#
|
|
1086
|
+
def rmb_click_cb(sender, sel, event)
|
|
1087
|
+
rooms, links = get_selection
|
|
1088
|
+
|
|
1089
|
+
menu = nil
|
|
1090
|
+
if not links.empty? and links.size == 1
|
|
1091
|
+
c = links[0]
|
|
1092
|
+
a = c.roomA
|
|
1093
|
+
b = c.roomB
|
|
1094
|
+
menu = FXMenuPane.new(@window)
|
|
1095
|
+
if c.dir == Connection::AtoB
|
|
1096
|
+
cmd = FXMenuCommand.new(menu, "Flip Direction")
|
|
1097
|
+
cmd.connect(SEL_COMMAND) { c.flip; draw }
|
|
1098
|
+
FXMenuSeparator.new(menu)
|
|
1099
|
+
end
|
|
1100
|
+
|
|
1101
|
+
submenu = FXMenuPane.new(@window)
|
|
1102
|
+
old_idx = a.exits.index(c)
|
|
1103
|
+
0.upto(7) { |idx|
|
|
1104
|
+
rmb_link_menu( submenu, c, a, idx, old_idx )
|
|
1105
|
+
}
|
|
1106
|
+
FXMenuCascade.new(menu, a.name, nil, submenu)
|
|
1107
|
+
if b
|
|
1108
|
+
submenu = FXMenuPane.new(@window)
|
|
1109
|
+
old_idx = b.exits.rindex(c)
|
|
1110
|
+
0.upto(7) { |idx|
|
|
1111
|
+
rmb_link_menu( submenu, c, b, idx, old_idx )
|
|
1112
|
+
}
|
|
1113
|
+
FXMenuCascade.new(menu, b.name, nil, submenu)
|
|
1114
|
+
end
|
|
1115
|
+
end
|
|
1116
|
+
if menu
|
|
1117
|
+
menu.create
|
|
1118
|
+
menu.popup(nil, event.root_x, event.root_y)
|
|
1119
|
+
@window.getApp.runModalWhileShown(menu)
|
|
1120
|
+
end
|
|
1121
|
+
end
|
|
1122
|
+
|
|
1123
|
+
|
|
1124
|
+
#
|
|
1125
|
+
# Handle left mouse button click
|
|
1126
|
+
#
|
|
1127
|
+
def lmb_click_cb(sender, sel, event)
|
|
1128
|
+
x = (event.last_x / @zoom).to_i
|
|
1129
|
+
y = (event.last_y / @zoom).to_i
|
|
1130
|
+
|
|
1131
|
+
if event.state & ALTMASK != 0
|
|
1132
|
+
mmb_click_cb(sender, sel, event)
|
|
1133
|
+
return
|
|
1134
|
+
end
|
|
1135
|
+
|
|
1136
|
+
selection = to_object(x, y)
|
|
1137
|
+
|
|
1138
|
+
if event.state & SHIFTMASK != 0
|
|
1139
|
+
@mouseButton = LEFTBUTTON
|
|
1140
|
+
@canvas.grab
|
|
1141
|
+
@dx, @dy = [ x, y ]
|
|
1142
|
+
return if not selection
|
|
1143
|
+
end
|
|
1144
|
+
|
|
1145
|
+
|
|
1146
|
+
if event.click_count == 2
|
|
1147
|
+
double_click_cb(selection, event)
|
|
1148
|
+
return
|
|
1149
|
+
end
|
|
1150
|
+
|
|
1151
|
+
unless selection
|
|
1152
|
+
clear_selection
|
|
1153
|
+
|
|
1154
|
+
# If in navigation mode, we don't allow user to modify map.
|
|
1155
|
+
return if @navigation
|
|
1156
|
+
|
|
1157
|
+
# if we did not select anything, check to see if we
|
|
1158
|
+
# clicked in a room area or connection area.
|
|
1159
|
+
if click_type(x, y)
|
|
1160
|
+
return if @complexConnection
|
|
1161
|
+
# Add a new room
|
|
1162
|
+
roomB = @sections[@section].rooms[-1]
|
|
1163
|
+
roomA = new_xy_room( x, y )
|
|
1164
|
+
if roomB and roomA and @options['Automatic Connection']
|
|
1165
|
+
# check to see if rooms are next to each other
|
|
1166
|
+
# if so, try to connect them (assuming there's no connection there
|
|
1167
|
+
# already).
|
|
1168
|
+
exitB = roomB.next_to?(roomA)
|
|
1169
|
+
if exitB and roomB.exits[exitB] == nil
|
|
1170
|
+
new_connection( roomB, exitB, roomA )
|
|
1171
|
+
end
|
|
1172
|
+
end
|
|
1173
|
+
else
|
|
1174
|
+
# Add a new connection
|
|
1175
|
+
if @complexConnection
|
|
1176
|
+
new_complex_connection(x, y)
|
|
1177
|
+
else
|
|
1178
|
+
# Add a new simple connection (plus rooms if needed)
|
|
1179
|
+
if event.state & CONTROLMASK != 0
|
|
1180
|
+
exitA = get_quadrant(x, y)
|
|
1181
|
+
roomA, roomB, a, b = quadrant_to_rooms( exitA, x, y )
|
|
1182
|
+
if not roomA
|
|
1183
|
+
new_xy_connection( x, y )
|
|
1184
|
+
else
|
|
1185
|
+
if a and roomA
|
|
1186
|
+
@complexConnection = [roomA, exitA]
|
|
1187
|
+
new_connection( roomA, exitA, nil )
|
|
1188
|
+
_new_complex_connection( roomA, exitA )
|
|
1189
|
+
end
|
|
1190
|
+
end
|
|
1191
|
+
else
|
|
1192
|
+
new_xy_connection( x, y )
|
|
1193
|
+
end
|
|
1194
|
+
end
|
|
1195
|
+
end
|
|
1196
|
+
else
|
|
1197
|
+
if selection.kind_of?(Connection) and selection.selected
|
|
1198
|
+
# Toggle arrow direction
|
|
1199
|
+
selection.toggle_direction
|
|
1200
|
+
draw
|
|
1201
|
+
return
|
|
1202
|
+
else
|
|
1203
|
+
if event.state & SHIFTMASK == 0 and
|
|
1204
|
+
event.state & CONTROLMASK == 0
|
|
1205
|
+
clear_selection
|
|
1206
|
+
end
|
|
1207
|
+
# Select the stuff
|
|
1208
|
+
selection.update_properties(self)
|
|
1209
|
+
if event.state & CONTROLMASK != 0
|
|
1210
|
+
selection.selected ^= true # toggle selection
|
|
1211
|
+
else
|
|
1212
|
+
selection.selected = true
|
|
1213
|
+
end
|
|
1214
|
+
end
|
|
1215
|
+
end
|
|
1216
|
+
draw(sender, sel, event)
|
|
1217
|
+
end
|
|
1218
|
+
|
|
1219
|
+
#
|
|
1220
|
+
# Close the map. Pop up a warning box to allow saving
|
|
1221
|
+
# if map has been modified.
|
|
1222
|
+
#
|
|
1223
|
+
def close_cb()
|
|
1224
|
+
if @modified
|
|
1225
|
+
dlg = FXDialogBox.new( @window.parent, "Warning",
|
|
1226
|
+
DECOR_ALL,
|
|
1227
|
+
0, 0, 400, 130)
|
|
1228
|
+
# Frame
|
|
1229
|
+
s = FXVerticalFrame.new(dlg,
|
|
1230
|
+
LAYOUT_SIDE_TOP|LAYOUT_FILL_X)
|
|
1231
|
+
|
|
1232
|
+
f = FXHorizontalFrame.new(s, LAYOUT_SIDE_TOP|LAYOUT_FILL_X|LAYOUT_FILL_Y)
|
|
1233
|
+
|
|
1234
|
+
font = FXFont.new(@window.getApp, "Helvetica", 30)
|
|
1235
|
+
font.create
|
|
1236
|
+
oops = FXLabel.new(f, "!", nil, 0, LAYOUT_SIDE_LEFT|LAYOUT_FILL_X|
|
|
1237
|
+
LAYOUT_CENTER_Y)
|
|
1238
|
+
oops.frameStyle = FRAME_RAISED|FRAME_THICK
|
|
1239
|
+
oops.baseColor = 'dark grey'
|
|
1240
|
+
oops.textColor = 'red'
|
|
1241
|
+
oops.padLeft = oops.padRight = 15
|
|
1242
|
+
oops.shadowColor = 'black'
|
|
1243
|
+
oops.borderColor = 'white'
|
|
1244
|
+
oops.font = font
|
|
1245
|
+
|
|
1246
|
+
FXLabel.new(f,
|
|
1247
|
+
"\n#{@name} #{MSG_WAS_MODIFIED}#{MSG_SHOULD_I_SAVE_CHANGES}",
|
|
1248
|
+
nil, 0)
|
|
1249
|
+
|
|
1250
|
+
# Separator
|
|
1251
|
+
FXHorizontalSeparator.new(s,
|
|
1252
|
+
LAYOUT_SIDE_TOP|LAYOUT_FILL_X|SEPARATOR_GROOVE)
|
|
1253
|
+
|
|
1254
|
+
# Bottom buttons
|
|
1255
|
+
buttons = FXHorizontalFrame.new(s,
|
|
1256
|
+
LAYOUT_SIDE_BOTTOM|FRAME_NONE|
|
|
1257
|
+
LAYOUT_FILL_X|PACK_UNIFORM_WIDTH)
|
|
1258
|
+
# Accept
|
|
1259
|
+
yes = FXButton.new(buttons, BUTTON_YES, nil, dlg, FXDialogBox::ID_ACCEPT,
|
|
1260
|
+
FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|
|
|
1261
|
+
LAYOUT_RIGHT|LAYOUT_CENTER_Y)
|
|
1262
|
+
yes.connect(SEL_COMMAND) {
|
|
1263
|
+
dlg.close
|
|
1264
|
+
if save
|
|
1265
|
+
@window.close
|
|
1266
|
+
return true
|
|
1267
|
+
else
|
|
1268
|
+
return false
|
|
1269
|
+
end
|
|
1270
|
+
}
|
|
1271
|
+
FXButton.new(buttons, BUTTON_NO, nil, dlg, FXDialogBox::ID_ACCEPT,
|
|
1272
|
+
FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|
|
|
1273
|
+
LAYOUT_RIGHT|LAYOUT_CENTER_Y)
|
|
1274
|
+
|
|
1275
|
+
# Cancel
|
|
1276
|
+
FXButton.new(buttons, BUTTON_CANCEL, nil, dlg, FXDialogBox::ID_CANCEL,
|
|
1277
|
+
FRAME_RAISED|FRAME_THICK|LAYOUT_FILL_X|
|
|
1278
|
+
LAYOUT_RIGHT|LAYOUT_CENTER_Y)
|
|
1279
|
+
yes.setDefault
|
|
1280
|
+
yes.setFocus
|
|
1281
|
+
|
|
1282
|
+
return false if dlg.execute == 0
|
|
1283
|
+
end
|
|
1284
|
+
@automap.destroy if @automap
|
|
1285
|
+
@automap = nil
|
|
1286
|
+
@window.close
|
|
1287
|
+
return true
|
|
1288
|
+
end
|
|
1289
|
+
|
|
1290
|
+
#
|
|
1291
|
+
# Create cursors
|
|
1292
|
+
#
|
|
1293
|
+
def _make_cursors
|
|
1294
|
+
pix = []
|
|
1295
|
+
32.times { 32.times { pix << 255 << 255 << 255 << 255 } }
|
|
1296
|
+
pix = pix.pack('c*')
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
['n', 'ne', 'e', 'se', 's', 'sw', 'w', 'nw'].each { |d|
|
|
1300
|
+
eval(<<-"EOF")
|
|
1301
|
+
@@cursor_#{d} = FXGIFCursor.new(@window.getApp, pix)
|
|
1302
|
+
FXFileStream.open('icons/room_#{d}.gif', FXStreamLoad) { |stream|
|
|
1303
|
+
@@cursor_#{d}.loadPixels(stream)
|
|
1304
|
+
}
|
|
1305
|
+
@@cursor_#{d}.create
|
|
1306
|
+
EOF
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
@@cursor_move = FXCursor.new(@window.getApp, CURSOR_MOVE)
|
|
1310
|
+
@@cursor_move.create
|
|
1311
|
+
|
|
1312
|
+
@@cursor_arrow = FXCursor.new(@window.getApp, CURSOR_ARROW)
|
|
1313
|
+
@@cursor_arrow.create
|
|
1314
|
+
|
|
1315
|
+
@@cursor_cross = FXCursor.new(@window.getApp, CURSOR_CROSS)
|
|
1316
|
+
@@cursor_cross.create
|
|
1317
|
+
end
|
|
1318
|
+
|
|
1319
|
+
#
|
|
1320
|
+
# Create widgets for this map window
|
|
1321
|
+
#
|
|
1322
|
+
def _make_widgets
|
|
1323
|
+
@scrollwindow = FXScrollWindow.new(@window,
|
|
1324
|
+
SCROLLERS_NORMAL|SCROLLERS_TRACK)
|
|
1325
|
+
width = WW * @width
|
|
1326
|
+
height = HH * @height
|
|
1327
|
+
|
|
1328
|
+
@canvasFrame = FXVerticalFrame.new(@scrollwindow,
|
|
1329
|
+
FRAME_SUNKEN|LAYOUT_FILL_X|
|
|
1330
|
+
LAYOUT_FILL_Y|LAYOUT_TOP|LAYOUT_LEFT)
|
|
1331
|
+
|
|
1332
|
+
# First, create an off-screen image for drawing and double buffering
|
|
1333
|
+
@image = FXBMPImage.new(@window.getApp, nil, IMAGE_SHMI|IMAGE_SHMP,
|
|
1334
|
+
width, height)
|
|
1335
|
+
@image.create
|
|
1336
|
+
|
|
1337
|
+
# Then create canvas
|
|
1338
|
+
@canvas = FXCanvas.new(@canvasFrame, nil, 0,
|
|
1339
|
+
LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT|
|
|
1340
|
+
LAYOUT_TOP|LAYOUT_LEFT,
|
|
1341
|
+
0, 0, width, height)
|
|
1342
|
+
@dirty = true
|
|
1343
|
+
# @canvas.connect(SEL_UPDATE, method(:update_cb))
|
|
1344
|
+
|
|
1345
|
+
@canvas.connect(SEL_PAINT, method(:draw))
|
|
1346
|
+
@canvas.backColor = @options['BG Color']
|
|
1347
|
+
|
|
1348
|
+
@canvas.connect(SEL_MOUSEWHEEL, method(:mousewheel_cb))
|
|
1349
|
+
@canvas.connect(SEL_LEFTBUTTONPRESS, method(:lmb_click_cb))
|
|
1350
|
+
@canvas.connect(SEL_LEFTBUTTONRELEASE, method(:mmb_release_cb))
|
|
1351
|
+
@canvas.connect(SEL_MOTION, method(:motion_cb))
|
|
1352
|
+
@canvas.connect(SEL_MIDDLEBUTTONPRESS, method(:mmb_click_cb))
|
|
1353
|
+
@canvas.connect(SEL_MIDDLEBUTTONRELEASE, method(:mmb_release_cb))
|
|
1354
|
+
@canvas.connect(SEL_RIGHTBUTTONPRESS, method(:rmb_click_cb))
|
|
1355
|
+
@canvas.connect(SEL_KEYPRESS, method(:keypress_cb))
|
|
1356
|
+
|
|
1357
|
+
if fxversion !~ /^1.2/
|
|
1358
|
+
@@tooltip = FXToolTip.new(@canvas.app, FXToolTip::TOOLTIP_PERMANENT)
|
|
1359
|
+
# Tooltip is too buggy and annoying. Turning it off for now.
|
|
1360
|
+
# @canvas.connect(SEL_QUERY_TIP, method(:tooltip_cb))
|
|
1361
|
+
end
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
#
|
|
1365
|
+
# Main constructor. Create the object, initialize the pathmap
|
|
1366
|
+
# and initialize the widgets and cursors if a parent window is passed.
|
|
1367
|
+
#
|
|
1368
|
+
def initialize(name, parent = nil, default_options = nil,
|
|
1369
|
+
icon = nil, menu = nil, mode = nil,
|
|
1370
|
+
x = 0, y = 0, w = 0, h = 0)
|
|
1371
|
+
@mutex = Mutex.new
|
|
1372
|
+
@automap = nil
|
|
1373
|
+
@navigation = false
|
|
1374
|
+
@modified = false
|
|
1375
|
+
@mouseButton = false
|
|
1376
|
+
@filename = nil
|
|
1377
|
+
@complexConnection = false
|
|
1378
|
+
super(name)
|
|
1379
|
+
if parent
|
|
1380
|
+
@window = FXMDIChild.new(parent, name, icon, menu, mode, x, y, w, h)
|
|
1381
|
+
@options = default_options
|
|
1382
|
+
_make_cursors if not @@cursor_arrow
|
|
1383
|
+
_make_widgets
|
|
1384
|
+
end
|
|
1385
|
+
empty_pathmap
|
|
1386
|
+
self.zoom = 0.8
|
|
1387
|
+
end
|
|
1388
|
+
|
|
1389
|
+
#
|
|
1390
|
+
# Handle 'cutting' any selected rooms and/or connections
|
|
1391
|
+
#
|
|
1392
|
+
def _cut_selected
|
|
1393
|
+
rooms = @sections[@section].rooms.find_all { |r| r.selected }
|
|
1394
|
+
conns = @sections[@section].connections.find_all { |c| c.selected }
|
|
1395
|
+
############################
|
|
1396
|
+
# First, handle rooms...
|
|
1397
|
+
############################
|
|
1398
|
+
# Remove rooms from path map
|
|
1399
|
+
rooms.each { |r| @pmap[r.x][r.y] = nil }
|
|
1400
|
+
# Remove rooms from current section in map
|
|
1401
|
+
@sections[@section].rooms -= rooms
|
|
1402
|
+
# Add any connections pointing to removed rooms as connection to remove
|
|
1403
|
+
rooms.each { |r|
|
|
1404
|
+
conns += r.exits.find_all { |e| e != nil }
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
#########################
|
|
1408
|
+
# Now, handle connections
|
|
1409
|
+
#########################
|
|
1410
|
+
conns.uniq!
|
|
1411
|
+
|
|
1412
|
+
# Remove connections from path map
|
|
1413
|
+
conns.each { |c| clean_path(c) }
|
|
1414
|
+
# Remove connections from current section in map
|
|
1415
|
+
@sections[@section].connections -= conns
|
|
1416
|
+
|
|
1417
|
+
return conns
|
|
1418
|
+
end
|
|
1419
|
+
|
|
1420
|
+
def cut_selected
|
|
1421
|
+
_cut_selected
|
|
1422
|
+
modified = true
|
|
1423
|
+
draw
|
|
1424
|
+
end
|
|
1425
|
+
|
|
1426
|
+
#
|
|
1427
|
+
# Handle deleting selected rooms and/or connections
|
|
1428
|
+
#
|
|
1429
|
+
def delete_selected
|
|
1430
|
+
conns = _cut_selected
|
|
1431
|
+
|
|
1432
|
+
# Remove room exits pointing to any removed connection
|
|
1433
|
+
conns.each { |c|
|
|
1434
|
+
a = c.roomA
|
|
1435
|
+
b = c.roomB
|
|
1436
|
+
a[a.exits.index(c)] = nil
|
|
1437
|
+
if b
|
|
1438
|
+
idx = b.exits.rindex(c)
|
|
1439
|
+
b[idx] = nil if idx
|
|
1440
|
+
end
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
if @complexConnection
|
|
1444
|
+
@complexConnection = false
|
|
1445
|
+
status MSG_COMPLEX_CONNECTION_STOPPED
|
|
1446
|
+
end
|
|
1447
|
+
|
|
1448
|
+
modified = true
|
|
1449
|
+
create_pathmap
|
|
1450
|
+
draw
|
|
1451
|
+
end
|
|
1452
|
+
|
|
1453
|
+
#
|
|
1454
|
+
# Start a complex connection
|
|
1455
|
+
#
|
|
1456
|
+
def complex_connection
|
|
1457
|
+
return if @complexConnection or @navigation
|
|
1458
|
+
@complexConnection = true
|
|
1459
|
+
status MSG_COMPLEX_CONNECTION
|
|
1460
|
+
end
|
|
1461
|
+
|
|
1462
|
+
#
|
|
1463
|
+
# Given a selection of rooms, clear all of them from path map
|
|
1464
|
+
#
|
|
1465
|
+
def clean_room_selection(selection)
|
|
1466
|
+
selection.each { |r|
|
|
1467
|
+
@pmap[r.x][r.y] = nil
|
|
1468
|
+
clean_exits(r)
|
|
1469
|
+
}
|
|
1470
|
+
end
|
|
1471
|
+
|
|
1472
|
+
#
|
|
1473
|
+
# Given a selection of rooms, clear all of them from path map
|
|
1474
|
+
#
|
|
1475
|
+
def store_room_selection(selection)
|
|
1476
|
+
selection.each { |r|
|
|
1477
|
+
@pmap[r.x][r.y] = r
|
|
1478
|
+
}
|
|
1479
|
+
update_exits(selection)
|
|
1480
|
+
end
|
|
1481
|
+
|
|
1482
|
+
#
|
|
1483
|
+
# Clean all paths from path map for a room
|
|
1484
|
+
#
|
|
1485
|
+
def clean_exits(room)
|
|
1486
|
+
room.exits.each { |c|
|
|
1487
|
+
next if not c
|
|
1488
|
+
clean_path(c)
|
|
1489
|
+
}
|
|
1490
|
+
end
|
|
1491
|
+
|
|
1492
|
+
def show_roomlist
|
|
1493
|
+
if @@roomlist
|
|
1494
|
+
@@roomlist.copy_from(self)
|
|
1495
|
+
else
|
|
1496
|
+
require 'IFMapper/FXRoomList'
|
|
1497
|
+
@@roomlist = FXRoomList.new(self)
|
|
1498
|
+
end
|
|
1499
|
+
@@roomlist.show
|
|
1500
|
+
end
|
|
1501
|
+
|
|
1502
|
+
def show_itemlist
|
|
1503
|
+
if @@itemlist
|
|
1504
|
+
@@itemlist.copy_from(self)
|
|
1505
|
+
else
|
|
1506
|
+
require 'IFMapper/FXItemList'
|
|
1507
|
+
@@itemlist = FXItemList.new(self)
|
|
1508
|
+
end
|
|
1509
|
+
@@itemlist.show
|
|
1510
|
+
end
|
|
1511
|
+
|
|
1512
|
+
def self.no_maps
|
|
1513
|
+
@@roomlist.hide if @@roomlist
|
|
1514
|
+
@@win.hide if @@win
|
|
1515
|
+
FXRoom::no_maps
|
|
1516
|
+
FXConnection::no_maps
|
|
1517
|
+
end
|
|
1518
|
+
|
|
1519
|
+
#
|
|
1520
|
+
# If roomlist window is present, update it
|
|
1521
|
+
#
|
|
1522
|
+
def update_roomlist
|
|
1523
|
+
@@roomlist.copy_from(self) if @@roomlist
|
|
1524
|
+
@@win.copy_from(self) if @@win
|
|
1525
|
+
end
|
|
1526
|
+
|
|
1527
|
+
#
|
|
1528
|
+
# Find and update all paths in path map for a room
|
|
1529
|
+
#
|
|
1530
|
+
def update_exits(selection)
|
|
1531
|
+
create_pathmap
|
|
1532
|
+
@modified = true
|
|
1533
|
+
end
|
|
1534
|
+
|
|
1535
|
+
|
|
1536
|
+
#
|
|
1537
|
+
# Return the current active room
|
|
1538
|
+
#
|
|
1539
|
+
def current_room
|
|
1540
|
+
rooms = @sections[@section].rooms.find_all { |r| r.selected }
|
|
1541
|
+
return nil if rooms.empty? or rooms.size > 1
|
|
1542
|
+
return rooms[0]
|
|
1543
|
+
end
|
|
1544
|
+
|
|
1545
|
+
def cannot_automap(why)
|
|
1546
|
+
w = FXWarningBox.new(@window, "#{ERR_CANNOT_AUTOMAP}\n#{why}")
|
|
1547
|
+
w.execute
|
|
1548
|
+
end
|
|
1549
|
+
|
|
1550
|
+
#
|
|
1551
|
+
# Give user some warning if he tries to modify a read-only mode.
|
|
1552
|
+
#
|
|
1553
|
+
def navigation_warning
|
|
1554
|
+
w = FXWarningBox.new(@window, ERR_READ_ONLY_MAP)
|
|
1555
|
+
w.execute
|
|
1556
|
+
end
|
|
1557
|
+
|
|
1558
|
+
|
|
1559
|
+
#
|
|
1560
|
+
# Move selected rooms in one of the 8 cardinal directions.
|
|
1561
|
+
#
|
|
1562
|
+
def move_to(idx)
|
|
1563
|
+
return navigation_warning if @navigation
|
|
1564
|
+
selection = @sections[@section].rooms.find_all { |r| r.selected }
|
|
1565
|
+
return if selection.empty?
|
|
1566
|
+
clean_room_selection(selection)
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
dx, dy = Room::DIR_TO_VECTOR[idx]
|
|
1570
|
+
|
|
1571
|
+
# Check that all nodes can be moved in the specified direction
|
|
1572
|
+
selection.each { |r|
|
|
1573
|
+
x = r.x + dx
|
|
1574
|
+
y = r.y + dy
|
|
1575
|
+
if x < 0 or y < 0 or x >= @width or y >= @height or
|
|
1576
|
+
@pmap.at(x).at(y).kind_of?(Room)
|
|
1577
|
+
store_room_selection(selection)
|
|
1578
|
+
dir = Room::DIRECTIONS[idx]
|
|
1579
|
+
status "#{ERR_CANNOT_MOVE_SELECTION} #{dir}."
|
|
1580
|
+
return
|
|
1581
|
+
end
|
|
1582
|
+
}
|
|
1583
|
+
selection.each { |r|
|
|
1584
|
+
r.x += dx
|
|
1585
|
+
r.y += dy
|
|
1586
|
+
}
|
|
1587
|
+
update_exits(selection)
|
|
1588
|
+
draw
|
|
1589
|
+
end
|
|
1590
|
+
|
|
1591
|
+
#
|
|
1592
|
+
# Move through an exit into another room. If exit is empty, create
|
|
1593
|
+
# a new neighboring room.
|
|
1594
|
+
#
|
|
1595
|
+
def move_thru(idx)
|
|
1596
|
+
room = current_room
|
|
1597
|
+
return if not room
|
|
1598
|
+
exit = room[idx]
|
|
1599
|
+
if exit
|
|
1600
|
+
room.selected = false
|
|
1601
|
+
if room == exit.roomA
|
|
1602
|
+
roomB = exit.roomB
|
|
1603
|
+
else
|
|
1604
|
+
roomB = exit.roomA
|
|
1605
|
+
end
|
|
1606
|
+
roomB.selected = true
|
|
1607
|
+
draw
|
|
1608
|
+
else
|
|
1609
|
+
return navigation_warning if @navigation
|
|
1610
|
+
x, y = room.x, room.y
|
|
1611
|
+
dx, dy = Room::DIR_TO_VECTOR[idx]
|
|
1612
|
+
x += dx
|
|
1613
|
+
y += dy
|
|
1614
|
+
x = 0 if x < 0
|
|
1615
|
+
y = 0 if y < 0
|
|
1616
|
+
x = @width-1 if x > @width-1
|
|
1617
|
+
y = @height-1 if y > @height-1
|
|
1618
|
+
if not @pmap.at(x).at(y).kind_of?(Room)
|
|
1619
|
+
room.selected = false
|
|
1620
|
+
roomB = new_xy_room(x * WW, y * HH)
|
|
1621
|
+
exitB = roomB.next_to?(room)
|
|
1622
|
+
if exitB and roomB.exits[exitB] == nil
|
|
1623
|
+
new_connection( roomB, exitB, room )
|
|
1624
|
+
end
|
|
1625
|
+
draw
|
|
1626
|
+
end
|
|
1627
|
+
end
|
|
1628
|
+
end
|
|
1629
|
+
|
|
1630
|
+
#
|
|
1631
|
+
# Handle a keypress
|
|
1632
|
+
#
|
|
1633
|
+
def keypress_cb( server, sel, event)
|
|
1634
|
+
case event.code
|
|
1635
|
+
when KEY_Escape
|
|
1636
|
+
if @complexConnection
|
|
1637
|
+
if @complexConnection.kind_of?(Array)
|
|
1638
|
+
@sections[@section].delete_connection_at(-1)
|
|
1639
|
+
status MSG_COMPLEX_CONNECTION_STOPPED
|
|
1640
|
+
draw
|
|
1641
|
+
end
|
|
1642
|
+
@complexConnection = false
|
|
1643
|
+
end
|
|
1644
|
+
when KEY_BackSpace, KEY_Delete
|
|
1645
|
+
return navigation_warning if @navigation
|
|
1646
|
+
delete_selected
|
|
1647
|
+
when KEY_c
|
|
1648
|
+
if event.state & CONTROLMASK != 0
|
|
1649
|
+
FXMapperWindow::copy_selected(self)
|
|
1650
|
+
draw
|
|
1651
|
+
end
|
|
1652
|
+
when KEY_v
|
|
1653
|
+
if event.state & CONTROLMASK != 0
|
|
1654
|
+
FXMapperWindow::paste_selected(self)
|
|
1655
|
+
@modified = true
|
|
1656
|
+
draw
|
|
1657
|
+
end
|
|
1658
|
+
when KEY_x
|
|
1659
|
+
return navigation_warning if @navigation
|
|
1660
|
+
if event.state & CONTROLMASK != 0
|
|
1661
|
+
FXMapperWindow::cut_selected(self)
|
|
1662
|
+
@modified = true
|
|
1663
|
+
draw
|
|
1664
|
+
else
|
|
1665
|
+
complex_connection
|
|
1666
|
+
end
|
|
1667
|
+
when KEY_plus
|
|
1668
|
+
zoom_in
|
|
1669
|
+
when KEY_minus
|
|
1670
|
+
zoom_out
|
|
1671
|
+
when KEY_KP_8
|
|
1672
|
+
move_thru(0)
|
|
1673
|
+
when KEY_KP_9
|
|
1674
|
+
move_thru(1)
|
|
1675
|
+
when KEY_KP_6
|
|
1676
|
+
move_thru(2)
|
|
1677
|
+
when KEY_KP_3
|
|
1678
|
+
move_thru(3)
|
|
1679
|
+
when KEY_KP_2
|
|
1680
|
+
move_thru(4)
|
|
1681
|
+
when KEY_KP_1
|
|
1682
|
+
move_thru(5)
|
|
1683
|
+
when KEY_KP_4
|
|
1684
|
+
move_thru(6)
|
|
1685
|
+
when KEY_KP_7
|
|
1686
|
+
move_thru(7)
|
|
1687
|
+
when KEY_Up
|
|
1688
|
+
move_to(0)
|
|
1689
|
+
when KEY_Down
|
|
1690
|
+
move_to(4)
|
|
1691
|
+
when KEY_Left
|
|
1692
|
+
move_to(6)
|
|
1693
|
+
when KEY_Right
|
|
1694
|
+
move_to(2)
|
|
1695
|
+
when KEY_End
|
|
1696
|
+
move_to(5)
|
|
1697
|
+
when KEY_Home
|
|
1698
|
+
move_to(7)
|
|
1699
|
+
when KEY_Page_Up
|
|
1700
|
+
move_to(1)
|
|
1701
|
+
when KEY_Page_Down
|
|
1702
|
+
move_to(3)
|
|
1703
|
+
end
|
|
1704
|
+
end
|
|
1705
|
+
|
|
1706
|
+
#
|
|
1707
|
+
# Draw template of diagonal connections in grid background
|
|
1708
|
+
#
|
|
1709
|
+
def draw_diagonal_connections(dc, event)
|
|
1710
|
+
ww = WW * @zoom
|
|
1711
|
+
hh = HH * @zoom
|
|
1712
|
+
|
|
1713
|
+
w = W * @zoom
|
|
1714
|
+
h = H * @zoom
|
|
1715
|
+
|
|
1716
|
+
ws = WS * @zoom
|
|
1717
|
+
hs = HS * @zoom
|
|
1718
|
+
|
|
1719
|
+
ws_2 = WS_2 * @zoom
|
|
1720
|
+
hs_2 = HS_2 * @zoom
|
|
1721
|
+
|
|
1722
|
+
maxy = @height - 1
|
|
1723
|
+
maxx = @width - 1
|
|
1724
|
+
|
|
1725
|
+
(0...@height).each { |yy|
|
|
1726
|
+
(0...@width).each { |xx|
|
|
1727
|
+
next if @pmap.at(xx).at(yy).kind_of?(Connection)
|
|
1728
|
+
x = xx * ww
|
|
1729
|
+
y = yy * hh
|
|
1730
|
+
|
|
1731
|
+
if yy < maxy and xx < maxx
|
|
1732
|
+
# First, draw \
|
|
1733
|
+
x1 = x + w + ws_2
|
|
1734
|
+
y1 = y + h + hs_2
|
|
1735
|
+
|
|
1736
|
+
x2 = x1 + ws
|
|
1737
|
+
y2 = y1 + hs
|
|
1738
|
+
dc.drawLine( x1, y1, x2, y2 )
|
|
1739
|
+
|
|
1740
|
+
end
|
|
1741
|
+
|
|
1742
|
+
if yy < maxy and xx > 0 and xx <= maxx
|
|
1743
|
+
# Then, draw /
|
|
1744
|
+
x1 = x + ws_2
|
|
1745
|
+
y1 = y + h + hs_2
|
|
1746
|
+
|
|
1747
|
+
x2 = x1 - ws
|
|
1748
|
+
y2 = y1 + hs
|
|
1749
|
+
dc.drawLine( x2, y2, x1, y1 )
|
|
1750
|
+
end
|
|
1751
|
+
}
|
|
1752
|
+
}
|
|
1753
|
+
end
|
|
1754
|
+
|
|
1755
|
+
#
|
|
1756
|
+
# Draw template of straight connections in grid background
|
|
1757
|
+
#
|
|
1758
|
+
def draw_straight_connections(dc, event)
|
|
1759
|
+
ww = WW * @zoom
|
|
1760
|
+
hh = HH * @zoom
|
|
1761
|
+
|
|
1762
|
+
w = W * @zoom
|
|
1763
|
+
h = H * @zoom
|
|
1764
|
+
|
|
1765
|
+
ws_2 = WS_2 * @zoom
|
|
1766
|
+
hs_2 = HS_2 * @zoom
|
|
1767
|
+
|
|
1768
|
+
#---- dummy check to catch an ugly bug that I cannot track...
|
|
1769
|
+
create_pathmap if @pmap.size < @width or @pmap[0].size < @height
|
|
1770
|
+
|
|
1771
|
+
# First, draw horizontal lines
|
|
1772
|
+
(0...@height).each { |yy|
|
|
1773
|
+
(0..@width-2).each { |xx|
|
|
1774
|
+
next if @pmap.at(xx).at(yy).kind_of?(Connection) or
|
|
1775
|
+
@pmap.at(xx+1).at(yy).kind_of?(Connection)
|
|
1776
|
+
x1 = xx * ww + w + ws_2
|
|
1777
|
+
x2 = (xx + 1) * ww + ws_2
|
|
1778
|
+
y1 = yy * hh + h / 2 + hs_2
|
|
1779
|
+
|
|
1780
|
+
dc.drawLine( x1, y1, x2, y1 )
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
# Then, draw vertical lines
|
|
1785
|
+
(0...@width).each { |xx|
|
|
1786
|
+
(0..@height-2).each { |yy|
|
|
1787
|
+
next if @pmap.at(xx).at(yy).kind_of?(Connection) or
|
|
1788
|
+
@pmap.at(xx).at(yy+1).kind_of?(Connection)
|
|
1789
|
+
x1 = xx * ww + w / 2 + ws_2
|
|
1790
|
+
y1 = yy * hh + h + hs_2
|
|
1791
|
+
y2 = (yy + 1) * hh + hs_2
|
|
1792
|
+
|
|
1793
|
+
dc.drawLine( x1, y1, x1, y2 )
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
end
|
|
1797
|
+
|
|
1798
|
+
|
|
1799
|
+
|
|
1800
|
+
#
|
|
1801
|
+
# Draw template of room squares in background
|
|
1802
|
+
#
|
|
1803
|
+
def draw_grid(dc, event = nil)
|
|
1804
|
+
|
|
1805
|
+
dc.foreground = "black"
|
|
1806
|
+
dc.lineWidth = 0
|
|
1807
|
+
dc.lineStyle = LINE_ONOFF_DASH
|
|
1808
|
+
|
|
1809
|
+
ww = WW * @zoom
|
|
1810
|
+
hh = HH * @zoom
|
|
1811
|
+
|
|
1812
|
+
w = W * @zoom
|
|
1813
|
+
h = H * @zoom
|
|
1814
|
+
|
|
1815
|
+
ws_2 = WS_2 * @zoom
|
|
1816
|
+
hs_2 = HS_2 * @zoom
|
|
1817
|
+
|
|
1818
|
+
(0...@width).each { |xx|
|
|
1819
|
+
(0...@height).each { |yy|
|
|
1820
|
+
next if @pmap.at(xx).at(yy)
|
|
1821
|
+
x = xx * ww + ws_2
|
|
1822
|
+
y = yy * hh + hs_2
|
|
1823
|
+
dc.drawRectangle( x, y, w, h )
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
end
|
|
1827
|
+
|
|
1828
|
+
#
|
|
1829
|
+
# Clean background to solid color
|
|
1830
|
+
#
|
|
1831
|
+
def draw_background(dc, event = nil)
|
|
1832
|
+
dc.foreground = @options['BG Color']
|
|
1833
|
+
dc.fillRectangle(0,0, @canvas.width, @canvas.height)
|
|
1834
|
+
end
|
|
1835
|
+
|
|
1836
|
+
#
|
|
1837
|
+
# Draw connections among rooms
|
|
1838
|
+
#
|
|
1839
|
+
def draw_connections(dc)
|
|
1840
|
+
dc.lineStyle = LINE_SOLID
|
|
1841
|
+
dc.lineWidth = 3 * @zoom
|
|
1842
|
+
dc.lineWidth = 3 if dc.lineWidth < 3
|
|
1843
|
+
@sections[@section].connections.each { |c| c.draw(dc, @zoom, @options) }
|
|
1844
|
+
end
|
|
1845
|
+
|
|
1846
|
+
#
|
|
1847
|
+
# Draw a single room (callback used when editing room dialog box)
|
|
1848
|
+
#
|
|
1849
|
+
def draw_room(room)
|
|
1850
|
+
idx = @sections[@section].rooms.index(room)
|
|
1851
|
+
return unless idx
|
|
1852
|
+
|
|
1853
|
+
dc = FXDCWindow.new(@canvas)
|
|
1854
|
+
dc.font = @font
|
|
1855
|
+
data = { }
|
|
1856
|
+
data['font'] = @font
|
|
1857
|
+
data['objfont'] = @objfont
|
|
1858
|
+
room.draw(dc, @zoom, idx, @options, data)
|
|
1859
|
+
dc.end
|
|
1860
|
+
end
|
|
1861
|
+
|
|
1862
|
+
#
|
|
1863
|
+
# Draw all rooms in current section
|
|
1864
|
+
#
|
|
1865
|
+
def draw_rooms(dc)
|
|
1866
|
+
data = { }
|
|
1867
|
+
data['font'] = @font
|
|
1868
|
+
data['objfont'] = @objfont
|
|
1869
|
+
@sections[@section].rooms.each_with_index { |room, idx|
|
|
1870
|
+
room.draw(dc, @zoom, idx, @options, data)
|
|
1871
|
+
}
|
|
1872
|
+
end
|
|
1873
|
+
|
|
1874
|
+
#
|
|
1875
|
+
# Draw mapname
|
|
1876
|
+
#
|
|
1877
|
+
def draw_mapname(dc)
|
|
1878
|
+
fontsize = (24 * @zoom).to_i
|
|
1879
|
+
font = FXFont.new(@window.getApp, @options['Font Text'], fontsize)
|
|
1880
|
+
font.create
|
|
1881
|
+
|
|
1882
|
+
x = @width * WW / 2.0 - @name.size * 24
|
|
1883
|
+
dc.drawText(x, 30, @name)
|
|
1884
|
+
end
|
|
1885
|
+
|
|
1886
|
+
#
|
|
1887
|
+
# Print map
|
|
1888
|
+
#
|
|
1889
|
+
def print(printer)
|
|
1890
|
+
# dc = FXDCPrint.new(@window.getApp)
|
|
1891
|
+
require 'IFMapper/MapPrinting'
|
|
1892
|
+
require 'IFMapper/FXDCPostscript'
|
|
1893
|
+
oldzoom = @zoom
|
|
1894
|
+
oldsection = @section
|
|
1895
|
+
self.zoom = 1.0
|
|
1896
|
+
|
|
1897
|
+
num = pack_sections( @width, @height )
|
|
1898
|
+
begin
|
|
1899
|
+
dc = FXDCPostscript.new(@window.getApp)
|
|
1900
|
+
xmax = @width * WW
|
|
1901
|
+
ymax = @height * HH
|
|
1902
|
+
dc.setContentRange(0, 0, xmax, ymax)
|
|
1903
|
+
dc.beginPrint(printer) {
|
|
1904
|
+
page = -1
|
|
1905
|
+
0.upto(@sections.size-1) { |p|
|
|
1906
|
+
self.section = p
|
|
1907
|
+
clear_selection
|
|
1908
|
+
if page != sect.page
|
|
1909
|
+
dc.beginPage(sect.page)
|
|
1910
|
+
draw_mapname( dc )
|
|
1911
|
+
end
|
|
1912
|
+
|
|
1913
|
+
dc.lineCap = CAP_ROUND
|
|
1914
|
+
# draw_grid(dc)
|
|
1915
|
+
draw_connections(dc)
|
|
1916
|
+
draw_rooms(dc)
|
|
1917
|
+
|
|
1918
|
+
if page != sect.page
|
|
1919
|
+
page = sect.page
|
|
1920
|
+
dc.endPage()
|
|
1921
|
+
end
|
|
1922
|
+
}
|
|
1923
|
+
}
|
|
1924
|
+
rescue => e
|
|
1925
|
+
status "#{e}"
|
|
1926
|
+
end
|
|
1927
|
+
self.section = oldsection
|
|
1928
|
+
self.zoom = oldzoom
|
|
1929
|
+
draw
|
|
1930
|
+
end
|
|
1931
|
+
|
|
1932
|
+
|
|
1933
|
+
#
|
|
1934
|
+
# Draw map
|
|
1935
|
+
#
|
|
1936
|
+
def draw(sender = nil, sel = nil, event = nil)
|
|
1937
|
+
return if @mutex.locked? or not @canvas.created?
|
|
1938
|
+
|
|
1939
|
+
if not @image.created?
|
|
1940
|
+
# puts "Image was not created. Try again"
|
|
1941
|
+
self.zoom = @zoom
|
|
1942
|
+
end
|
|
1943
|
+
|
|
1944
|
+
pos = @scrollwindow.position
|
|
1945
|
+
w = @scrollwindow.getViewportWidth
|
|
1946
|
+
h = @scrollwindow.getViewportHeight
|
|
1947
|
+
|
|
1948
|
+
# The -5 seems to be a bug in fox. don't ask me.
|
|
1949
|
+
cx = -pos[0]-5
|
|
1950
|
+
cx = 0 if cx < 0
|
|
1951
|
+
cy = -pos[1]-5
|
|
1952
|
+
cy = 0 if cy < 0
|
|
1953
|
+
|
|
1954
|
+
dc = FXDCWindow.new(@image)
|
|
1955
|
+
dc.setClipRectangle( cx, cy, w, h)
|
|
1956
|
+
dc.font = @font
|
|
1957
|
+
#dc.lineCap = CAP_ROUND
|
|
1958
|
+
draw_background(dc, event)
|
|
1959
|
+
draw_grid(dc, event) if @options['Grid Boxes']
|
|
1960
|
+
if @options['Grid Straight Connections']
|
|
1961
|
+
draw_straight_connections(dc, event)
|
|
1962
|
+
end
|
|
1963
|
+
if @options['Grid Diagonal Connections']
|
|
1964
|
+
draw_diagonal_connections(dc, event)
|
|
1965
|
+
end
|
|
1966
|
+
draw_connections(dc)
|
|
1967
|
+
draw_rooms(dc)
|
|
1968
|
+
dc.end
|
|
1969
|
+
|
|
1970
|
+
|
|
1971
|
+
# Blit the off-screen image into canvas
|
|
1972
|
+
dc = FXDCWindow.new(@canvas)
|
|
1973
|
+
dc.setClipRectangle( cx, cy, w, h)
|
|
1974
|
+
dc.drawImage(@image,0,0)
|
|
1975
|
+
dc.end
|
|
1976
|
+
|
|
1977
|
+
end
|
|
1978
|
+
|
|
1979
|
+
|
|
1980
|
+
#
|
|
1981
|
+
# Perform the actual saving of the map
|
|
1982
|
+
#
|
|
1983
|
+
def _save
|
|
1984
|
+
if @complexConnection
|
|
1985
|
+
# If we have an incomplete connection, remove it
|
|
1986
|
+
@sections[@section].delete_connection_at(-1)
|
|
1987
|
+
end
|
|
1988
|
+
|
|
1989
|
+
if @filename !~ /\.map$/i
|
|
1990
|
+
@filename << '.map'
|
|
1991
|
+
end
|
|
1992
|
+
|
|
1993
|
+
status "#{MSG_SAVING} '#{@filename}'..."
|
|
1994
|
+
|
|
1995
|
+
# Make sure we save a valid map. This is mainly a fail-safe
|
|
1996
|
+
# in case of an autosave due to a bug.
|
|
1997
|
+
verify_integrity
|
|
1998
|
+
|
|
1999
|
+
@version = FILE_FORMAT_VERSION
|
|
2000
|
+
begin
|
|
2001
|
+
f = File.open(@filename, "wb")
|
|
2002
|
+
f.puts Marshal.dump(self)
|
|
2003
|
+
f.close
|
|
2004
|
+
rescue => e
|
|
2005
|
+
status "#{ERR_COULD_NOT_SAVE} '#{@filename}': #{e}"
|
|
2006
|
+
sleep 4
|
|
2007
|
+
return false
|
|
2008
|
+
end
|
|
2009
|
+
@modified = false
|
|
2010
|
+
status "#{MSG_SAVED} '#{@filename}'."
|
|
2011
|
+
sleep 0.5
|
|
2012
|
+
return true
|
|
2013
|
+
end
|
|
2014
|
+
|
|
2015
|
+
#
|
|
2016
|
+
# Save the map. If the map's filename is not defined, call save_as
|
|
2017
|
+
#
|
|
2018
|
+
def save
|
|
2019
|
+
unless @filename
|
|
2020
|
+
save_as
|
|
2021
|
+
else
|
|
2022
|
+
_save
|
|
2023
|
+
end
|
|
2024
|
+
end
|
|
2025
|
+
|
|
2026
|
+
|
|
2027
|
+
#
|
|
2028
|
+
# Export map as an IFM map file
|
|
2029
|
+
#
|
|
2030
|
+
def export_ifm(file)
|
|
2031
|
+
require 'IFMapper/IFMWriter'
|
|
2032
|
+
file += '.ifm' if file !~ /\.ifm$/
|
|
2033
|
+
IFMWriter.new(self, file)
|
|
2034
|
+
end
|
|
2035
|
+
|
|
2036
|
+
|
|
2037
|
+
#
|
|
2038
|
+
# Export map as a set of TADS3 source code files
|
|
2039
|
+
#
|
|
2040
|
+
def export_tads(file)
|
|
2041
|
+
require 'IFMapper/TADSWriter'
|
|
2042
|
+
file.sub!(/(-\d+)?\.t/, '')
|
|
2043
|
+
TADSWriter.new(self, file)
|
|
2044
|
+
end
|
|
2045
|
+
|
|
2046
|
+
#
|
|
2047
|
+
# Export map as a set of Inform source code files
|
|
2048
|
+
#
|
|
2049
|
+
def export_inform7(file)
|
|
2050
|
+
require 'IFMapper/Inform7Writer'
|
|
2051
|
+
file.sub!(/.inform$/, '')
|
|
2052
|
+
Inform7Writer.new(self, file)
|
|
2053
|
+
end
|
|
2054
|
+
|
|
2055
|
+
#
|
|
2056
|
+
# Export map as a set of Inform source code files
|
|
2057
|
+
#
|
|
2058
|
+
def export_inform(file, version = 6)
|
|
2059
|
+
if file =~ /\.inform$/ or version > 6
|
|
2060
|
+
return export_inform7(file)
|
|
2061
|
+
end
|
|
2062
|
+
|
|
2063
|
+
require 'IFMapper/InformWriter'
|
|
2064
|
+
file.sub!(/(-\d+)?\.inf/, '')
|
|
2065
|
+
InformWriter.new(self, file)
|
|
2066
|
+
end
|
|
2067
|
+
|
|
2068
|
+
#
|
|
2069
|
+
# Save the map under a new filename, bringing up a file requester
|
|
2070
|
+
#
|
|
2071
|
+
def save_as
|
|
2072
|
+
require 'IFMapper/FXMapFileDialog'
|
|
2073
|
+
file = FXMapFileDialog.new(@window, "#{MSG_SAVE_MAP} #{@name}",
|
|
2074
|
+
FXMapFileDialog::KNOWN_SAVE_EXTENSIONS).filename
|
|
2075
|
+
if file != ''
|
|
2076
|
+
if File.exists?(file)
|
|
2077
|
+
dlg = FXWarningBox.new(@window, "#{file}\n#{WARN_OVERWRITE_MAP}")
|
|
2078
|
+
return if dlg.execute == 0
|
|
2079
|
+
end
|
|
2080
|
+
|
|
2081
|
+
case file
|
|
2082
|
+
when /\.inform$/, /\.inf$/
|
|
2083
|
+
export_inform(file)
|
|
2084
|
+
when /\.ifm$/
|
|
2085
|
+
export_ifm(file)
|
|
2086
|
+
when /\.t$/
|
|
2087
|
+
export_tads(file)
|
|
2088
|
+
else
|
|
2089
|
+
@filename = file
|
|
2090
|
+
return _save
|
|
2091
|
+
end
|
|
2092
|
+
end
|
|
2093
|
+
return false
|
|
2094
|
+
end
|
|
2095
|
+
|
|
2096
|
+
#
|
|
2097
|
+
# Open the map's property window
|
|
2098
|
+
#
|
|
2099
|
+
def properties
|
|
2100
|
+
if not @@win
|
|
2101
|
+
@@win = FXMapDialogBox.new(@window)
|
|
2102
|
+
end
|
|
2103
|
+
@@win.copy_from(self)
|
|
2104
|
+
@@win.show
|
|
2105
|
+
end
|
|
2106
|
+
|
|
2107
|
+
def stop_automap
|
|
2108
|
+
return unless @automap
|
|
2109
|
+
@automap.destroy
|
|
2110
|
+
@automap = nil
|
|
2111
|
+
GC.start
|
|
2112
|
+
update_title
|
|
2113
|
+
end
|
|
2114
|
+
|
|
2115
|
+
def start_automap
|
|
2116
|
+
if @automap
|
|
2117
|
+
stop_automap
|
|
2118
|
+
end
|
|
2119
|
+
require 'IFMapper/FXMapFileDialog'
|
|
2120
|
+
file = FXMapFileDialog.new(@window, MSG_LOAD_TRANSCRIPT,
|
|
2121
|
+
[
|
|
2122
|
+
EXT_TRANSCRIPT,
|
|
2123
|
+
EXT_ALL_FILES
|
|
2124
|
+
]).filename
|
|
2125
|
+
return if file == ''
|
|
2126
|
+
require 'IFMapper/TranscriptReader'
|
|
2127
|
+
|
|
2128
|
+
begin
|
|
2129
|
+
@automap = TranscriptReader.new(self, file)
|
|
2130
|
+
@automap.properties(true)
|
|
2131
|
+
@automap.start
|
|
2132
|
+
rescue Errno::EACCES, Errno::ENOENT => e
|
|
2133
|
+
dlg = FXWarningBox.new(@window, "#{ERR_CANNOT_OPEN_TRANSCRIPT}\n#{e}")
|
|
2134
|
+
dlg.execute
|
|
2135
|
+
return
|
|
2136
|
+
rescue => e
|
|
2137
|
+
puts e.backtrace
|
|
2138
|
+
dlg = FXWarningBox.new(@window, "#{ERR_PARSE_TRANSCRIPT}\n#{e}\n#{e.backtrace}")
|
|
2139
|
+
dlg.execute
|
|
2140
|
+
raise
|
|
2141
|
+
end
|
|
2142
|
+
create_pathmap
|
|
2143
|
+
draw
|
|
2144
|
+
update_title
|
|
2145
|
+
end
|
|
2146
|
+
|
|
2147
|
+
end
|