ifmapper 0.8.5 → 0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/HISTORY.txt +110 -0
- data/IFMapper.gemspec +1 -1
- data/TODO.txt +6 -2
- data/lib/IFMapper/Connection.rb +2 -1
- data/lib/IFMapper/FXConnection.rb +36 -18
- data/lib/IFMapper/FXConnectionDialogBox.rb +10 -2
- data/lib/IFMapper/FXMap.rb +68 -28
- data/lib/IFMapper/FXMapFileDialog.rb +1 -1
- data/lib/IFMapper/FXMapperSettings.rb +15 -5
- data/lib/IFMapper/FXMapperWindow.rb +102 -8
- data/lib/IFMapper/FXRoom.rb +1 -3
- data/lib/IFMapper/FXRoomDialogBox.rb +52 -16
- data/lib/IFMapper/FXSection.rb +9 -0
- data/lib/IFMapper/IFMReader.rb +5 -3
- data/lib/IFMapper/InformReader.rb +803 -0
- data/lib/IFMapper/InformReaderOld.rb +778 -0
- data/lib/IFMapper/InformWriter.rb +349 -0
- data/lib/IFMapper/Map.rb +12 -0
- data/lib/IFMapper/PDFMapExporter.rb +35 -17
- data/lib/IFMapper/Room.rb +4 -1
- data/lib/IFMapper/Section.rb +17 -3
- data/lib/IFMapper/TADSReader.rb +832 -0
- data/lib/IFMapper/TADSWriter.rb +360 -0
- data/lib/IFMapper/TranscriptReader.rb +167 -49
- metadata +16 -11
data/HISTORY.txt
CHANGED
@@ -1,3 +1,113 @@
|
|
1
|
+
v0.9 - What's new:
|
2
|
+
|
3
|
+
- Fixed a very idiotic bug in Cut algorithm. It was basically destroying
|
4
|
+
all cut connections right after they were cut.
|
5
|
+
|
6
|
+
- Editing rooms' names or objects now results in a much, much
|
7
|
+
faster redraw of the map, even if map is very complex.
|
8
|
+
|
9
|
+
- You can now display and edit a location's description. This
|
10
|
+
description is often used by the the automapper during transcript
|
11
|
+
mapping to determine the uniqueness of a room, albeit the main
|
12
|
+
use of editing a room description is to allow creation of
|
13
|
+
new games (currently, Inform).
|
14
|
+
|
15
|
+
- You can now optionally avoid displaying the task or description
|
16
|
+
section on rooms.
|
17
|
+
This is mainly to allow you to read maps that have walkthru tasks
|
18
|
+
in them without giving away the game.
|
19
|
+
|
20
|
+
- IFMapper now supports the concept of closed but unlocked doors.
|
21
|
+
These will be displayed as a white square between connections.
|
22
|
+
The main interest of placing these doors is for creation
|
23
|
+
of new Inform games, not so much for solving games.
|
24
|
+
|
25
|
+
- You can now select exit stubs. Useful for deleting them when
|
26
|
+
automapper detects them incorrectly.
|
27
|
+
|
28
|
+
- Saving and Loading a map will now verify the integrity of the map
|
29
|
+
is correct. This prevets autosave from saving a corrupt map if
|
30
|
+
there is a bug in the program.
|
31
|
+
|
32
|
+
- CTRL-Selection is a toggle selection. That is, if you click once
|
33
|
+
on something already selected, it is deselected.
|
34
|
+
|
35
|
+
- Automapper improvements
|
36
|
+
* Automapper will now deal with complex commands involving 'then'
|
37
|
+
a tad better.
|
38
|
+
* An additional fix to dark rooms. Looking in a dark room would
|
39
|
+
result in the dark room being created, even if the room had
|
40
|
+
already been tagged as dark. Fixed.
|
41
|
+
* When choosing an up/down/in/out/random move direction, a new
|
42
|
+
connection will not be generated if there is already a similar
|
43
|
+
n/s/e/w/etc. link between the two rooms. This helps to simplify
|
44
|
+
some maps.
|
45
|
+
* Automapper now will try to automatically remove stub exits that
|
46
|
+
are not really exits if the user tries to move in that direction
|
47
|
+
and fails.
|
48
|
+
* Automapping was incorrectly reporting a maze when a new exit
|
49
|
+
would point in the same direction as a visited up/down or in/out
|
50
|
+
exit.
|
51
|
+
* Room descriptions are now compared (and stored) without \n at the
|
52
|
+
end of each line. This helps with comparing descriptions with any
|
53
|
+
description the user typed manually.
|
54
|
+
* Automapper will no longer crash if a link is attempted between
|
55
|
+
two rooms in different sections, nor will it corrupt your map as
|
56
|
+
it did before.
|
57
|
+
* Automapper is now a tad smarter in not considering words such
|
58
|
+
as open/close in descriptions. This helps the automapper not
|
59
|
+
get confused if a door which is part of the room description
|
60
|
+
changes state.
|
61
|
+
|
62
|
+
- Inform support.
|
63
|
+
|
64
|
+
* You can now read an inform file and automap it, with
|
65
|
+
some limitations.
|
66
|
+
The main limitation deals with how doors are handled, as Inform
|
67
|
+
offers an almost infinite number of ways of dealing with doors,
|
68
|
+
including the use of at least one of 4 popular libraries. Some
|
69
|
+
code will actually resolve issues of where doors lead to within,
|
70
|
+
for example, the "Enter" or "Exit" command, making parsing .inf
|
71
|
+
files impossible without writing a full inform compiler.
|
72
|
+
A second limitation is that Inform allows doors that exist only
|
73
|
+
on one "side" of a room. These exits will be ignored.
|
74
|
+
The inform automapper should prove compatible with most door
|
75
|
+
libraries, but will probably choke on a lot of hand-coded code.
|
76
|
+
|
77
|
+
* You can now export a map as an Inform .inf (source code) file.
|
78
|
+
This can be helpful at the beginning of designing a game to place
|
79
|
+
all objects/characters, doors and room descriptions easily.
|
80
|
+
Obviously, these source code files will later get hacked heavily
|
81
|
+
manually to provide the real game functionality.
|
82
|
+
IFMapper just gives you a start, helping you design
|
83
|
+
the landscape a tad more easily.
|
84
|
+
Doors are created in Inform using Andrew MacKinnon's easydoors
|
85
|
+
Inform extension.
|
86
|
+
|
87
|
+
NOTE: A word of warning about reading Inform or TADS maps.
|
88
|
+
Since these file formats have no concept of 'sections', they
|
89
|
+
can lead to some **HUGE** maps. The original Adventure, for
|
90
|
+
example, results in a 100x100 map. These huge maps may run
|
91
|
+
into memory issues and currently make the path-finding algorithm
|
92
|
+
work extremely slow.
|
93
|
+
|
94
|
+
- TADS 3 support
|
95
|
+
|
96
|
+
* NOTE: TADS 2 is currently *NOT* supported.
|
97
|
+
|
98
|
+
* You can now read a TADS 3 file and automap it, with some
|
99
|
+
limitations.
|
100
|
+
Basically, TADS 3 templates are currently *NOT* supported.
|
101
|
+
Instead, the standard library templates are kind of hard-coded
|
102
|
+
in the reader.
|
103
|
+
TADS 3's standard lib is more sensible than Inform when it
|
104
|
+
comes to doors, so it should hopefully lead to less
|
105
|
+
problems there.
|
106
|
+
|
107
|
+
* You can now export a TADS 3 (.t) file. Same concept as Inform,
|
108
|
+
albeit doors are created using TADS3 standard door classes.
|
109
|
+
|
110
|
+
|
1
111
|
|
2
112
|
v0.8.5 - This is mainly a bug fix release.
|
3
113
|
|
data/IFMapper.gemspec
CHANGED
@@ -2,7 +2,7 @@ require "rubygems"
|
|
2
2
|
|
3
3
|
spec = Gem::Specification.new do |spec|
|
4
4
|
spec.name = "ifmapper"
|
5
|
-
spec.version = '0.
|
5
|
+
spec.version = '0.9'
|
6
6
|
spec.author = "Gonzalo Garramuno"
|
7
7
|
spec.email = 'ggarram@advance.dsl.com.ar'
|
8
8
|
spec.homepage = 'http://www.rubyforge.org/projects/ifmapper/'
|
data/TODO.txt
CHANGED
@@ -1,7 +1,11 @@
|
|
1
1
|
|
2
|
+
- Ability to remove stub exits if moving in a certain direction fails.
|
3
|
+
Need to trap 'fail' messages for moving such as:
|
4
|
+
You can't go that way.
|
5
|
+
|
6
|
+
|
2
7
|
- Add SVG output
|
3
8
|
- Do Printing
|
4
|
-
- Cleanup code
|
5
|
-
between PDF/PS output)
|
9
|
+
- Cleanup code
|
6
10
|
- Improve window scrolling (seems like an FXRuby bug)
|
7
11
|
- Add Undo (at least for delete)
|
data/lib/IFMapper/Connection.rb
CHANGED
@@ -13,6 +13,7 @@ class Connection
|
|
13
13
|
FREE = 0
|
14
14
|
LOCKED_DOOR = 1
|
15
15
|
SPECIAL = 2
|
16
|
+
CLOSED_DOOR = 3
|
16
17
|
|
17
18
|
# Direction constants
|
18
19
|
BOTH = 0
|
@@ -73,7 +74,7 @@ class Connection
|
|
73
74
|
dirB = Room::DIRECTIONS[idx] if idx
|
74
75
|
end
|
75
76
|
end
|
76
|
-
"#{a} #{dirA
|
77
|
+
"#{a} #{dirA}<->#{b} #{dirB}"
|
77
78
|
end
|
78
79
|
end
|
79
80
|
|
@@ -60,7 +60,7 @@ class FXConnection < Connection
|
|
60
60
|
# window is open, copy the connection data to it.
|
61
61
|
#
|
62
62
|
def selected=(value)
|
63
|
-
@@win.copy_from(self) if value and @@win
|
63
|
+
@@win.copy_from(self) if value and @@win and @@win.shown?
|
64
64
|
@selected = value
|
65
65
|
end
|
66
66
|
|
@@ -205,6 +205,37 @@ class FXConnection < Connection
|
|
205
205
|
return dc.drawBSpline( p )
|
206
206
|
end
|
207
207
|
|
208
|
+
#
|
209
|
+
# Draw a door
|
210
|
+
#
|
211
|
+
def draw_door(dc, zoom, x1, y1, x2, y2)
|
212
|
+
v = [ (x2-x1), (y2-y1) ]
|
213
|
+
t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
214
|
+
v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
|
215
|
+
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
216
|
+
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
217
|
+
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
218
|
+
if @type == LOCKED_DOOR
|
219
|
+
# Locked door
|
220
|
+
dc.drawLine(x1, y1, x2, y2)
|
221
|
+
else
|
222
|
+
# open door
|
223
|
+
v = [ v[0] / 3, v[1] / 3]
|
224
|
+
x1, y1 = x1.to_i, y1.to_i
|
225
|
+
x2, y2 = x2.to_i, y2.to_i
|
226
|
+
pts = []
|
227
|
+
pts << FXPoint.new(x1 - v[0], y1 - v[1])
|
228
|
+
pts << FXPoint.new(x1 + v[0], y1 + v[1])
|
229
|
+
pts << FXPoint.new(x2 + v[0], y2 + v[1])
|
230
|
+
pts << FXPoint.new(x2 - v[0], y2 - v[1])
|
231
|
+
pts << pts[0]
|
232
|
+
width = dc.lineWidth
|
233
|
+
dc.lineWidth = 0
|
234
|
+
dc.drawLines(pts)
|
235
|
+
dc.lineWidth = width
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
208
239
|
#
|
209
240
|
# Draw a complex connection
|
210
241
|
#
|
@@ -219,18 +250,11 @@ class FXConnection < Connection
|
|
219
250
|
x2, y2 = [p[-1].x, p[-1].y]
|
220
251
|
draw_arrow(dc, zoom, x1, y1, x2, y2)
|
221
252
|
|
222
|
-
if @type == LOCKED_DOOR
|
253
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
223
254
|
t = p.size / 2
|
224
255
|
x1, y1 = [ p[t].x, p[t].y ]
|
225
256
|
x2, y2 = [ p[t-2].x, p[t-2].y ]
|
226
|
-
|
227
|
-
v = [ (x2-x1), (y2-y1) ]
|
228
|
-
t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
229
|
-
v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
|
230
|
-
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
231
|
-
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
232
|
-
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
233
|
-
dc.drawLine(x1, y1, x2, y2)
|
257
|
+
draw_door(dc, zoom, x1, y1, x2, y2)
|
234
258
|
end
|
235
259
|
end
|
236
260
|
|
@@ -245,14 +269,8 @@ class FXConnection < Connection
|
|
245
269
|
x2, y2 = @roomB.corner(self, zoom)
|
246
270
|
dc.drawLine( x1, y1, x2, y2 )
|
247
271
|
draw_arrow(dc, zoom, x1, y1, x2, y2)
|
248
|
-
if @type == LOCKED_DOOR
|
249
|
-
|
250
|
-
t = 10 * zoom / Math.sqrt(v[0]*v[0]+v[1]*v[1])
|
251
|
-
v = [ (v[0]*t).to_i, (v[1]*t).to_i ]
|
252
|
-
m = [ (x2+x1)/2, (y2+y1)/2 ]
|
253
|
-
x1, y1 = [m[0] + v[1], m[1] - v[0]]
|
254
|
-
x2, y2 = [m[0] - v[1], m[1] + v[0]]
|
255
|
-
dc.drawLine(x1, y1, x2, y2)
|
272
|
+
if @type == LOCKED_DOOR or @type == CLOSED_DOOR
|
273
|
+
draw_door(dc, zoom, x1, y1, x2, y2)
|
256
274
|
end
|
257
275
|
else
|
258
276
|
# Complex connection in progress or "stub" exit
|
@@ -6,10 +6,18 @@ class FXConnectionDialogBox < FXDialogBox
|
|
6
6
|
|
7
7
|
TYPE_TEXT = [
|
8
8
|
'Free',
|
9
|
+
'Door',
|
9
10
|
'Locked',
|
10
11
|
'Special',
|
11
12
|
]
|
12
13
|
|
14
|
+
TYPE_NUM = [
|
15
|
+
Connection::FREE, # free
|
16
|
+
Connection::CLOSED_DOOR, # door
|
17
|
+
Connection::LOCKED_DOOR, # locked
|
18
|
+
Connection::SPECIAL, # special
|
19
|
+
]
|
20
|
+
|
13
21
|
DIR_TEXT = [
|
14
22
|
'Both',
|
15
23
|
'A to B',
|
@@ -28,7 +36,7 @@ class FXConnectionDialogBox < FXDialogBox
|
|
28
36
|
|
29
37
|
def copy_to()
|
30
38
|
@conn.dir = @dir.currentNo
|
31
|
-
@conn.type = @type.currentNo
|
39
|
+
@conn.type = TYPE_NUM[ @type.currentNo ]
|
32
40
|
@conn.exitAtext = @exitA.currentNo
|
33
41
|
@conn.exitBtext = @exitB.currentNo
|
34
42
|
|
@@ -41,7 +49,7 @@ class FXConnectionDialogBox < FXDialogBox
|
|
41
49
|
self.title = title
|
42
50
|
|
43
51
|
@dir.currentNo = conn.dir
|
44
|
-
@type.currentNo = conn.type || 0
|
52
|
+
@type.currentNo = TYPE_NUM.index(conn.type) || 0
|
45
53
|
@exitA.currentNo = conn.exitAtext
|
46
54
|
@exitB.currentNo = conn.exitBtext
|
47
55
|
@conn = conn
|
data/lib/IFMapper/FXMap.rb
CHANGED
@@ -53,13 +53,6 @@ class FXMap < Map
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
-
#
|
57
|
-
# Fit all rooms in map, adjusting map size if needed
|
58
|
-
#
|
59
|
-
def fit
|
60
|
-
super
|
61
|
-
create_pathmap
|
62
|
-
end
|
63
56
|
|
64
57
|
#
|
65
58
|
# Jump to a certain section #
|
@@ -241,10 +234,10 @@ class FXMap < Map
|
|
241
234
|
b = c.roomB
|
242
235
|
|
243
236
|
dirA = a.exits.index(c)
|
244
|
-
raise "connection not found #{c} at #{a}" unless dirA
|
237
|
+
raise "A connection not found #{c} at #{a}" unless dirA
|
245
238
|
|
246
239
|
dirB = b.exits.rindex(c)
|
247
|
-
raise "connection not found #{c} at #{b}" unless dirB
|
240
|
+
raise "B connection not found #{c} at #{b}" unless dirB
|
248
241
|
|
249
242
|
vA = FXRoom::DIR_TO_VECTOR[dirA]
|
250
243
|
vB = FXRoom::DIR_TO_VECTOR[dirB]
|
@@ -284,6 +277,12 @@ class FXMap < Map
|
|
284
277
|
return false
|
285
278
|
end
|
286
279
|
|
280
|
+
if (pA[0] - pB[0]).abs > 30 or
|
281
|
+
(pA[1] - pB[1]).abs > 30
|
282
|
+
c.failed = true
|
283
|
+
return
|
284
|
+
end
|
285
|
+
|
287
286
|
# No, okay, we need to do true A* path finding
|
288
287
|
c.failed = false
|
289
288
|
aStar = AStar.new
|
@@ -433,7 +432,7 @@ class FXMap < Map
|
|
433
432
|
@sections[@section].connections.each { |c|
|
434
433
|
a = c.roomA
|
435
434
|
b = c.roomB
|
436
|
-
next if not b
|
435
|
+
next if not b and @complexConnection
|
437
436
|
|
438
437
|
if c.gpts.size > 0
|
439
438
|
2.times { |t|
|
@@ -467,7 +466,15 @@ class FXMap < Map
|
|
467
466
|
}
|
468
467
|
else
|
469
468
|
x1, y1 = a.corner(c, 1, a.exits.index(c))
|
470
|
-
|
469
|
+
if b
|
470
|
+
x2, y2 = b.corner(c, 1, b.exits.rindex(c))
|
471
|
+
else
|
472
|
+
dir = a.exits.index(c)
|
473
|
+
v = FXRoom::DIR_TO_VECTOR[dir]
|
474
|
+
x2 = x1 + v[0] * WS
|
475
|
+
y2 = y1 + v[1] * HS
|
476
|
+
end
|
477
|
+
|
471
478
|
x1, x2 = x2, x1 if x2 < x1
|
472
479
|
y1, y2 = y2, y1 if y2 < y1
|
473
480
|
if x1 == x2
|
@@ -530,6 +537,7 @@ class FXMap < Map
|
|
530
537
|
# Then, create an off-screen image with that same size for double
|
531
538
|
# buffering
|
532
539
|
@image.destroy
|
540
|
+
GC.start
|
533
541
|
@image = FXBMPImage.new(@window.getApp, nil, IMAGE_SHMI|IMAGE_SHMP,
|
534
542
|
width, height)
|
535
543
|
@image.create
|
@@ -731,7 +739,7 @@ class FXMap < Map
|
|
731
739
|
|
732
740
|
# Self-explanatory.
|
733
741
|
def zoom_out
|
734
|
-
if @zoom > 0.
|
742
|
+
if @zoom > 0.1
|
735
743
|
self.zoom -= 0.1
|
736
744
|
end
|
737
745
|
end
|
@@ -1136,13 +1144,16 @@ class FXMap < Map
|
|
1136
1144
|
draw
|
1137
1145
|
return
|
1138
1146
|
else
|
1139
|
-
if event.state & SHIFTMASK == 0
|
1140
|
-
event.state & CONTROLMASK == 0
|
1147
|
+
if event.state & SHIFTMASK == 0
|
1141
1148
|
clear_selection
|
1142
1149
|
end
|
1143
1150
|
# Select the stuff
|
1144
1151
|
selection.update_properties(self)
|
1145
|
-
|
1152
|
+
if event.state & CONTROLMASK == 0
|
1153
|
+
selection.selected ^= true # toggle selection
|
1154
|
+
else
|
1155
|
+
selection.selected = true
|
1156
|
+
end
|
1146
1157
|
end
|
1147
1158
|
end
|
1148
1159
|
draw(sender, sel, event)
|
@@ -1315,11 +1326,10 @@ class FXMap < Map
|
|
1315
1326
|
self.zoom = 0.8
|
1316
1327
|
end
|
1317
1328
|
|
1318
|
-
|
1319
1329
|
#
|
1320
|
-
# Handle
|
1330
|
+
# Handle 'cutting' any selected rooms and/or connections
|
1321
1331
|
#
|
1322
|
-
def
|
1332
|
+
def _cut_selected
|
1323
1333
|
rooms = @sections[@section].rooms.find_all { |r| r.selected }
|
1324
1334
|
conns = @sections[@section].connections.find_all { |c| c.selected }
|
1325
1335
|
############################
|
@@ -1343,6 +1353,22 @@ class FXMap < Map
|
|
1343
1353
|
conns.each { |c| clean_path(c) }
|
1344
1354
|
# Remove connections from current section in map
|
1345
1355
|
@sections[@section].connections -= conns
|
1356
|
+
|
1357
|
+
return conns
|
1358
|
+
end
|
1359
|
+
|
1360
|
+
def cut_selected
|
1361
|
+
_cut_selected
|
1362
|
+
modified = true
|
1363
|
+
draw
|
1364
|
+
end
|
1365
|
+
|
1366
|
+
#
|
1367
|
+
# Handle deleting selected rooms and/or connections
|
1368
|
+
#
|
1369
|
+
def delete_selected
|
1370
|
+
conns = _cut_selected
|
1371
|
+
|
1346
1372
|
# Remove room exits pointing to any removed connection
|
1347
1373
|
conns.each { |c|
|
1348
1374
|
a = c.roomA
|
@@ -1354,10 +1380,8 @@ class FXMap < Map
|
|
1354
1380
|
end
|
1355
1381
|
}
|
1356
1382
|
|
1357
|
-
|
1358
|
-
|
1359
|
-
create_pathmap
|
1360
|
-
draw()
|
1383
|
+
modified = true
|
1384
|
+
draw
|
1361
1385
|
end
|
1362
1386
|
|
1363
1387
|
#
|
@@ -1705,12 +1729,7 @@ class FXMap < Map
|
|
1705
1729
|
#
|
1706
1730
|
def draw_background(dc, event = nil)
|
1707
1731
|
dc.foreground = @options['BG Color']
|
1708
|
-
|
1709
|
-
if event
|
1710
|
-
dc.fillRectangle(event.rect.x, event.rect.y, event.rect.w, event.rect.h)
|
1711
|
-
else
|
1712
|
-
dc.fillRectangle(0,0, @canvas.width, @canvas.height)
|
1713
|
-
end
|
1732
|
+
dc.fillRectangle(0,0, @canvas.width, @canvas.height)
|
1714
1733
|
end
|
1715
1734
|
|
1716
1735
|
#
|
@@ -1794,6 +1813,22 @@ class FXMap < Map
|
|
1794
1813
|
draw
|
1795
1814
|
end
|
1796
1815
|
|
1816
|
+
#
|
1817
|
+
# Draw a single room (callback used when editing room dialog box)
|
1818
|
+
#
|
1819
|
+
def draw_room(room)
|
1820
|
+
idx = @sections[@section].rooms.index(room)
|
1821
|
+
return unless idx
|
1822
|
+
|
1823
|
+
dc = FXDCWindow.new(@canvas)
|
1824
|
+
dc.font = @font
|
1825
|
+
data = { }
|
1826
|
+
data['font'] = @font
|
1827
|
+
data['objfont'] = @objfont
|
1828
|
+
room.draw(dc, @zoom, idx, @options, data)
|
1829
|
+
dc.end
|
1830
|
+
end
|
1831
|
+
|
1797
1832
|
#
|
1798
1833
|
# Draw map
|
1799
1834
|
#
|
@@ -1846,6 +1881,11 @@ class FXMap < Map
|
|
1846
1881
|
end
|
1847
1882
|
|
1848
1883
|
status "Saving '#{@filename}'..."
|
1884
|
+
|
1885
|
+
# Make sure we save a valid map. This is mainly a fail-safe
|
1886
|
+
# in case of an autosave due to a bug.
|
1887
|
+
verify_integrity
|
1888
|
+
|
1849
1889
|
@version = FILE_FORMAT_VERSION
|
1850
1890
|
begin
|
1851
1891
|
f = File.open(@filename, "wb")
|