ifmapper 0.9.8 → 0.9.9
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 +7 -0
- data/lib/IFMapper/FXMap.rb +15 -2
- data/lib/IFMapper/FXMapperWindow.rb +27 -3
- data/lib/IFMapper/FXRoomList.rb +1 -1
- data/lib/IFMapper/Inform7Writer.rb +496 -0
- data/lib/IFMapper/InformWriter.rb +3 -5
- data/lib/IFMapper/Room.rb +2 -1
- data/lib/IFMapper/TADSWriter.rb +1 -4
- data/lib/IFMapper/TranscriptReader.rb +3 -1
- data/maps/A New Life.map +0 -0
- data/maps/Bronze.map +0 -0
- data/maps/Reliques_of_Tolti_Alph.map +0 -0
- data/maps/WinterWonderland.map +0 -0
- data/maps/anchor.map +0 -0
- data/maps/kaged.map +0 -0
- data/maps/muldoon_legacy.map +0 -0
- data/maps/simple.map +0 -0
- data/maps/zerosum.map +0 -0
- metadata +237 -229
- data/docs/start.html~ +0 -516
data/HISTORY.txt
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
v0.9.9 Improvements:
|
2
|
+
- It is now possible to export maps in Inform 7 new (beta) syntax,
|
3
|
+
albeit the English grammar is still very limited.
|
4
|
+
Just name your map with extension ".inform" instead of ".inf"
|
5
|
+
when saving it or exporting it.
|
6
|
+
- Bug fixed wrap_text() in all exporters.
|
7
|
+
|
1
8
|
v0.9.8 Bug fixes:
|
2
9
|
- TADS Exporter was incorrectly recognizing locations with "room" in
|
3
10
|
them as keywords and adding numbers to their tags. Fixed.
|
data/lib/IFMapper/FXMap.rb
CHANGED
@@ -2014,7 +2014,20 @@ class FXMap < Map
|
|
2014
2014
|
#
|
2015
2015
|
# Export map as a set of Inform source code files
|
2016
2016
|
#
|
2017
|
-
def
|
2017
|
+
def export_inform7(file)
|
2018
|
+
require 'IFMapper/Inform7Writer'
|
2019
|
+
file.sub!(/.inform$/, '')
|
2020
|
+
Inform7Writer.new(self, file)
|
2021
|
+
end
|
2022
|
+
|
2023
|
+
#
|
2024
|
+
# Export map as a set of Inform source code files
|
2025
|
+
#
|
2026
|
+
def export_inform(file, version = 6)
|
2027
|
+
if file =~ /\.inform$/ or version > 6
|
2028
|
+
return export_inform7(file)
|
2029
|
+
end
|
2030
|
+
|
2018
2031
|
require 'IFMapper/InformWriter'
|
2019
2032
|
file.sub!(/(-\d+)?\.inf/, '')
|
2020
2033
|
InformWriter.new(self, file)
|
@@ -2032,7 +2045,7 @@ class FXMap < Map
|
|
2032
2045
|
end
|
2033
2046
|
|
2034
2047
|
case file
|
2035
|
-
when /\.inf$/
|
2048
|
+
when /\.inform$/, /\.inf$/
|
2036
2049
|
export_inform(file)
|
2037
2050
|
when /\.ifm$/
|
2038
2051
|
export_ifm(file)
|
@@ -9,7 +9,7 @@ end
|
|
9
9
|
def no_fox
|
10
10
|
$stderr.puts "Please install the FXRuby (FOX) library v1.2 or later."
|
11
11
|
if $rubygems
|
12
|
-
$stderr.puts "You can usually do so if you do 'gem install fxruby'."
|
12
|
+
$stderr.puts "You can usually do so if you do 'gem install -r fxruby'."
|
13
13
|
end
|
14
14
|
exit(1)
|
15
15
|
end
|
@@ -17,7 +17,7 @@ end
|
|
17
17
|
def get_fox
|
18
18
|
##### ARRRGH!!!! Why does Lyle keep changing the fxruby name on each
|
19
19
|
##### release!
|
20
|
-
foxes = [ 'fox14', 'fox12', 'fox' ]
|
20
|
+
foxes = [ 'fox16', 'fox14', 'fox12', 'fox' ]
|
21
21
|
foxes.each { |fox|
|
22
22
|
begin
|
23
23
|
require "#{fox}"
|
@@ -128,6 +128,9 @@ class FXMapperWindow < FXMainWindow
|
|
128
128
|
map.start_automap
|
129
129
|
end
|
130
130
|
|
131
|
+
#
|
132
|
+
# Properties of the automapper callback
|
133
|
+
#
|
131
134
|
def automap_properties_cb(sender, sel, ptr)
|
132
135
|
map = current_map
|
133
136
|
return if not map or not map.automap
|
@@ -143,6 +146,10 @@ class FXMapperWindow < FXMainWindow
|
|
143
146
|
map.stop_automap
|
144
147
|
end
|
145
148
|
|
149
|
+
|
150
|
+
#
|
151
|
+
# Callback to Open File
|
152
|
+
#
|
146
153
|
def open_cb(sender, sel, ptr)
|
147
154
|
file = FXMapFileDialog.new(self, "Load New Map").filename
|
148
155
|
return if file == ''
|
@@ -216,10 +223,16 @@ class FXMapperWindow < FXMainWindow
|
|
216
223
|
status "Loaded '#{file}'."
|
217
224
|
end
|
218
225
|
|
226
|
+
#
|
227
|
+
# Write a message to the status bar
|
228
|
+
#
|
219
229
|
def status(msg)
|
220
230
|
@statusbar.statusLine.text = msg
|
221
231
|
end
|
222
232
|
|
233
|
+
#
|
234
|
+
# Returns current active map or nil if no maps
|
235
|
+
#
|
223
236
|
def current_map
|
224
237
|
window = @mdiclient.activeChild
|
225
238
|
return nil unless window
|
@@ -230,18 +243,27 @@ class FXMapperWindow < FXMainWindow
|
|
230
243
|
return nil
|
231
244
|
end
|
232
245
|
|
246
|
+
#
|
247
|
+
# Callback for Save
|
248
|
+
#
|
233
249
|
def save_cb(sender, sel, ptr)
|
234
250
|
map = current_map
|
235
251
|
return unless map
|
236
252
|
map.save
|
237
253
|
end
|
238
254
|
|
255
|
+
#
|
256
|
+
# Callback for Save As
|
257
|
+
#
|
239
258
|
def save_as_cb(sender, sel, ptr)
|
240
259
|
map = current_map
|
241
260
|
return unless map
|
242
261
|
map.save_as
|
243
262
|
end
|
244
263
|
|
264
|
+
#
|
265
|
+
# Callback used to create new map
|
266
|
+
#
|
245
267
|
def new_map_cb(*args)
|
246
268
|
m = new_map
|
247
269
|
m.window.create
|
@@ -275,7 +297,9 @@ class FXMapperWindow < FXMainWindow
|
|
275
297
|
return map
|
276
298
|
end
|
277
299
|
|
300
|
+
#
|
278
301
|
# Load the named PNG icon from a file
|
302
|
+
#
|
279
303
|
def load_icon(filename)
|
280
304
|
begin
|
281
305
|
filename = File.join("icons", filename) + ".png"
|
@@ -358,7 +382,7 @@ class FXMapperWindow < FXMainWindow
|
|
358
382
|
|
359
383
|
d = FXMapFileDialog.new(self, "Save Map as Inform Files",
|
360
384
|
[
|
361
|
-
"Inform Source Code (*.inf)"
|
385
|
+
"Inform Source Code (*.inf,*.inform)",
|
362
386
|
])
|
363
387
|
map.export_inform( d.filename ) if d.filename != ''
|
364
388
|
end
|
data/lib/IFMapper/FXRoomList.rb
CHANGED
@@ -0,0 +1,496 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
class Inform7Writer
|
4
|
+
|
5
|
+
|
6
|
+
DIRECTIONS = [
|
7
|
+
'North',
|
8
|
+
'Northeast',
|
9
|
+
'East',
|
10
|
+
'Southeast',
|
11
|
+
'South',
|
12
|
+
'Southwest',
|
13
|
+
'West',
|
14
|
+
'Northwest',
|
15
|
+
]
|
16
|
+
|
17
|
+
OTHERDIRS = [
|
18
|
+
'',
|
19
|
+
'Above',
|
20
|
+
'Below',
|
21
|
+
'Inside',
|
22
|
+
'Outside',
|
23
|
+
]
|
24
|
+
|
25
|
+
IGNORE_WORDS = [
|
26
|
+
'a', 'the', 'and', 'of', 'your', 'to'
|
27
|
+
]
|
28
|
+
|
29
|
+
IGNORED_ARTICLES = /^(?:#{IGNORE_WORDS.join('|')})$/
|
30
|
+
|
31
|
+
|
32
|
+
|
33
|
+
KEYWORDS = [
|
34
|
+
'include',
|
35
|
+
'has',
|
36
|
+
'with',
|
37
|
+
'is',
|
38
|
+
'in',
|
39
|
+
'inside',
|
40
|
+
]
|
41
|
+
INVALID_KEYWORD = /\b(?:#{KEYWORDS.join('|')})\b/i
|
42
|
+
|
43
|
+
|
44
|
+
LOCATION_NAMES = [
|
45
|
+
'door',
|
46
|
+
'include',
|
47
|
+
'room',
|
48
|
+
'has',
|
49
|
+
'with',
|
50
|
+
'is',
|
51
|
+
'container',
|
52
|
+
] + DIRECTIONS
|
53
|
+
INVALID_LOCATION_NAME = /^(?:#{LOCATION_NAMES.join('|')})$/i
|
54
|
+
|
55
|
+
|
56
|
+
#
|
57
|
+
# Some common animals in adventure games
|
58
|
+
#
|
59
|
+
ANIMALS = [
|
60
|
+
'horse',
|
61
|
+
'donkey',
|
62
|
+
'mule',
|
63
|
+
'goat',
|
64
|
+
# lizards
|
65
|
+
'lizard',
|
66
|
+
'snake',
|
67
|
+
'turtle',
|
68
|
+
# fishes
|
69
|
+
'fish',
|
70
|
+
'dolphin',
|
71
|
+
'whale',
|
72
|
+
'tortoise',
|
73
|
+
# dogs
|
74
|
+
'dog',
|
75
|
+
'wolf',
|
76
|
+
# cats
|
77
|
+
'cat',
|
78
|
+
'leopard',
|
79
|
+
'tiger',
|
80
|
+
'lion',
|
81
|
+
# fantastic
|
82
|
+
'grue',
|
83
|
+
# birds
|
84
|
+
'bird',
|
85
|
+
'pigeon',
|
86
|
+
'peacock',
|
87
|
+
'eagle',
|
88
|
+
]
|
89
|
+
|
90
|
+
IS_ANIMAL = /\b(?:#{ANIMALS.join('|')})\b/i
|
91
|
+
|
92
|
+
PEOPLE = [
|
93
|
+
'child',
|
94
|
+
'girl',
|
95
|
+
'woman',
|
96
|
+
'lady',
|
97
|
+
'boy',
|
98
|
+
'man',
|
99
|
+
'attendant',
|
100
|
+
'doctor',
|
101
|
+
'engineer',
|
102
|
+
'bum',
|
103
|
+
'nerd',
|
104
|
+
'ghost',
|
105
|
+
]
|
106
|
+
|
107
|
+
IS_PERSON = /\b(?:#{PEOPLE.join('|')})\b/i
|
108
|
+
|
109
|
+
#
|
110
|
+
# Some common container types
|
111
|
+
#
|
112
|
+
CONTAINERS = [
|
113
|
+
'box',
|
114
|
+
'cup',
|
115
|
+
'crate',
|
116
|
+
'tin',
|
117
|
+
'can',
|
118
|
+
'chest',
|
119
|
+
'wardrobe',
|
120
|
+
'trophy case',
|
121
|
+
'coffin',
|
122
|
+
'briefcase',
|
123
|
+
'suitcase',
|
124
|
+
'bag',
|
125
|
+
]
|
126
|
+
IS_CONTAINER = /\b(?:#{CONTAINERS.join('|')})\b/i
|
127
|
+
|
128
|
+
#
|
129
|
+
# Some common wearable types
|
130
|
+
#
|
131
|
+
CLOTHES = [
|
132
|
+
'cape',
|
133
|
+
'glove',
|
134
|
+
'jeans',
|
135
|
+
'trousers',
|
136
|
+
'hat',
|
137
|
+
'gown',
|
138
|
+
'backpack',
|
139
|
+
'shirt',
|
140
|
+
'ring',
|
141
|
+
'bracelet',
|
142
|
+
'amulet',
|
143
|
+
'locket',
|
144
|
+
]
|
145
|
+
IS_WEARABLE = /\b(?:#{CLOTHES.join('|')})\b/i
|
146
|
+
|
147
|
+
#
|
148
|
+
# Some common supporter types
|
149
|
+
#
|
150
|
+
SUPPORTERS = [
|
151
|
+
'table',
|
152
|
+
'shelf',
|
153
|
+
]
|
154
|
+
IS_SUPPORTER = /\b(?:#{SUPPORTERS.join('|')})\b/i
|
155
|
+
|
156
|
+
#
|
157
|
+
# Some common edible types
|
158
|
+
#
|
159
|
+
FOOD = [
|
160
|
+
'bread',
|
161
|
+
'cake',
|
162
|
+
# drinks
|
163
|
+
'water',
|
164
|
+
'soda',
|
165
|
+
'beer',
|
166
|
+
'beverage',
|
167
|
+
'potion',
|
168
|
+
# fruits
|
169
|
+
'fruit',
|
170
|
+
'apple',
|
171
|
+
'orange',
|
172
|
+
'banana',
|
173
|
+
'almond',
|
174
|
+
'nut',
|
175
|
+
]
|
176
|
+
IS_EDIBLE = /\b(?:#{FOOD.join('|')})\b/i
|
177
|
+
|
178
|
+
def new_tag(elem, str)
|
179
|
+
tag = str.dup
|
180
|
+
|
181
|
+
# Remove redundant spaces
|
182
|
+
tag.sub!(/^\s/, '')
|
183
|
+
tag.sub!(/\s$/, '')
|
184
|
+
|
185
|
+
# Invalid tag characters, replaced with _
|
186
|
+
tag.gsub!(/[\s"\\\#\,\.:;!\?\n\(\)]+/,'_')
|
187
|
+
tag.sub!(/^([\d]+)_?(.*)/, '\2\1') # No numbers allowed at start of tag
|
188
|
+
|
189
|
+
tag.gsub!(/__/, '_')
|
190
|
+
|
191
|
+
tag.upcase! # All tags are uppercase
|
192
|
+
|
193
|
+
# tag cannot be repeated and cannot be keyword (Doorway, Room, etc)
|
194
|
+
# In those cases, we add a number to the tag name.
|
195
|
+
idx = 0
|
196
|
+
if @tags.values.include?(tag) or tag =~ INVALID_LOCATION_NAME
|
197
|
+
idx = 1
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
|
202
|
+
if idx > 0
|
203
|
+
root = tag.dup
|
204
|
+
tag = "#{root}#{idx}"
|
205
|
+
while @tags.values.include?(tag)
|
206
|
+
tag = "#{root}#{idx}"
|
207
|
+
idx += 1
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
|
212
|
+
if elem.kind_of?(String)
|
213
|
+
@tags[tag] = tag
|
214
|
+
else
|
215
|
+
@tags[elem] = tag
|
216
|
+
end
|
217
|
+
return tag
|
218
|
+
end
|
219
|
+
|
220
|
+
def get_tag(elem, name = elem.name)
|
221
|
+
return @tags[elem] if @tags[elem]
|
222
|
+
return new_tag(elem, name)
|
223
|
+
end
|
224
|
+
|
225
|
+
def get_door_name(e)
|
226
|
+
dirA = e.roomA.exits.index(e)
|
227
|
+
dirB = e.roomB.exits.rindex(e)
|
228
|
+
name = DIRECTIONS[dirA].downcase + "-" + DIRECTIONS[dirB].downcase
|
229
|
+
name << " door"
|
230
|
+
end
|
231
|
+
|
232
|
+
def get_door_tag(e)
|
233
|
+
get_tag(e, get_door_name(e))
|
234
|
+
end
|
235
|
+
|
236
|
+
def wrap_text(text, width = 75, indent = 78 - width)
|
237
|
+
return 'UNDER CONSTRUCTION' if not text or text == ''
|
238
|
+
str = inform_quote( text.dup )
|
239
|
+
|
240
|
+
if str.size > width
|
241
|
+
r = ''
|
242
|
+
while str
|
243
|
+
idx = str.rindex(/[ -]/, width)
|
244
|
+
idx = str.size unless idx
|
245
|
+
r << str[0..idx]
|
246
|
+
str = str[idx+1..-1]
|
247
|
+
r << "\n" << ' ' * indent if str
|
248
|
+
end
|
249
|
+
return r
|
250
|
+
else
|
251
|
+
return str
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
#
|
257
|
+
# Take a text and quote it for inform's double-quote text areas.
|
258
|
+
#
|
259
|
+
def inform_quote(text)
|
260
|
+
str = text.dup
|
261
|
+
# Quote special characters
|
262
|
+
# str.gsub!(/@/, '@@64')
|
263
|
+
str.gsub!(/"/, '\'')
|
264
|
+
# str.gsub!(/~/, '@@126')
|
265
|
+
# str.gsub!(/\\/, '@@92')
|
266
|
+
# str.gsub!(/\^/, '@@94')
|
267
|
+
return str
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
def objects(r)
|
272
|
+
room = get_tag(r)
|
273
|
+
objs = r.objects.split("\n")
|
274
|
+
objs.each { |o|
|
275
|
+
|
276
|
+
tag = new_tag(o, o)
|
277
|
+
|
278
|
+
names = o.dup
|
279
|
+
names.gsub!(/"/, '') # remove any quotes
|
280
|
+
names.gsub!(/\b\w\b/, '') # remove single letter words
|
281
|
+
|
282
|
+
name = names
|
283
|
+
names = name.split(' ')
|
284
|
+
|
285
|
+
article = 'a '
|
286
|
+
if name =~ /ves$/ or name =~ /s$/
|
287
|
+
article = 'some '
|
288
|
+
elsif name[0,1] == 'a'
|
289
|
+
article = 'an '
|
290
|
+
end
|
291
|
+
|
292
|
+
|
293
|
+
# If name begins with uppercase, assume it is an NPC
|
294
|
+
type = 'a thing'
|
295
|
+
|
296
|
+
if name =~ IS_ANIMAL
|
297
|
+
type = 'an animal'
|
298
|
+
elsif name =~ IS_PERSON or name =~ /[A-Z]/
|
299
|
+
if name !~ /'/ # possesive, like Michael's wallet
|
300
|
+
# if too many words, probably a book's title
|
301
|
+
if names.size <= 3
|
302
|
+
article = ''
|
303
|
+
if name =~ /^(?:Miss|Mrs)/
|
304
|
+
type = 'a woman'
|
305
|
+
else
|
306
|
+
type = 'a person'
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
props = ''
|
314
|
+
|
315
|
+
if tag != name
|
316
|
+
props << "\n The printed name of #{tag} is \"#{article}#{name}\"."
|
317
|
+
end
|
318
|
+
|
319
|
+
if name =~ IS_CONTAINER
|
320
|
+
props << "\n It is a container."
|
321
|
+
end
|
322
|
+
|
323
|
+
if name =~ IS_SUPPORTER
|
324
|
+
props << "\n It is a supporter."
|
325
|
+
end
|
326
|
+
|
327
|
+
if name =~ IS_WEARABLE
|
328
|
+
props << "\n It is wearable."
|
329
|
+
end
|
330
|
+
|
331
|
+
if name =~ IS_EDIBLE
|
332
|
+
props << "\n It is edible."
|
333
|
+
end
|
334
|
+
|
335
|
+
@f.print <<"EOF"
|
336
|
+
|
337
|
+
In #{room}, there is #{type} called #{tag}. #{props}
|
338
|
+
The description of #{tag} is \"UNDER CONSTRUCTION.\"
|
339
|
+
EOF
|
340
|
+
if names.size > 1
|
341
|
+
names.each { |n|
|
342
|
+
next if n =~ IGNORED_ARTICLES
|
343
|
+
@f.puts " Understand \"#{n}\" as #{tag}."
|
344
|
+
}
|
345
|
+
end
|
346
|
+
}
|
347
|
+
|
348
|
+
|
349
|
+
end
|
350
|
+
|
351
|
+
def door(e)
|
352
|
+
name = get_door_name(e)
|
353
|
+
tag = get_tag(e, name)
|
354
|
+
roomA = get_tag(e.roomA)
|
355
|
+
roomB = get_tag(e.roomB)
|
356
|
+
dirA = e.roomA.exits.index(e)
|
357
|
+
dirB = e.roomB.exits.rindex(e)
|
358
|
+
dirA = DIRECTIONS[dirA].downcase
|
359
|
+
dirB = DIRECTIONS[dirB].downcase
|
360
|
+
|
361
|
+
props = ''
|
362
|
+
if e.type == Connection::LOCKED_DOOR
|
363
|
+
props = "It is locked."
|
364
|
+
elsif e.type == Connection::CLOSED_DOOR
|
365
|
+
props = "It is closed."
|
366
|
+
end
|
367
|
+
|
368
|
+
found_in = 'It is '
|
369
|
+
if e.dir == Connection::BOTH
|
370
|
+
found_in << "#{dirA} of #{roomA} and #{dirB} of #{roomB}"
|
371
|
+
elsif e.dir == Connection::AtoB
|
372
|
+
found_in << "#{dirA} of #{roomA}. Through it is #{roomB}"
|
373
|
+
elsif e.dir == Connection::BtoA
|
374
|
+
found_in << "#{dirB} of #{roomB}. Through it is #{roomA}"
|
375
|
+
end
|
376
|
+
|
377
|
+
@f.puts <<"EOF"
|
378
|
+
|
379
|
+
The #{tag} is a door. #{props}
|
380
|
+
The printed name of #{tag} is "a #{name}".
|
381
|
+
Understand "door" as #{tag}.
|
382
|
+
#{found_in}.
|
383
|
+
EOF
|
384
|
+
|
385
|
+
end
|
386
|
+
|
387
|
+
|
388
|
+
def room(r)
|
389
|
+
tag = get_tag(r)
|
390
|
+
name = r.name
|
391
|
+
|
392
|
+
prop = ''
|
393
|
+
if r.darkness
|
394
|
+
prop << 'dark '
|
395
|
+
end
|
396
|
+
|
397
|
+
@f.print "\n#{tag} is a #{prop}room."
|
398
|
+
|
399
|
+
if name != tag
|
400
|
+
name = inform_quote(name)
|
401
|
+
@f.print " The printed name of #{tag} is \"#{name}\"."
|
402
|
+
end
|
403
|
+
|
404
|
+
@f.puts
|
405
|
+
@f.puts " \"#{wrap_text(r.desc)}\""
|
406
|
+
|
407
|
+
# Now, handle exits...
|
408
|
+
r.exits.each_with_index { |e, dir|
|
409
|
+
next if (not e) or e.stub? or e.type == Connection::SPECIAL
|
410
|
+
if e.roomB == r
|
411
|
+
next if e.dir == Connection::AtoB
|
412
|
+
text = e.exitBtext
|
413
|
+
b = e.roomA
|
414
|
+
else
|
415
|
+
next if e.dir == Connection::BtoA
|
416
|
+
text = e.exitAtext
|
417
|
+
b = e.roomB
|
418
|
+
end
|
419
|
+
@f.print ' '
|
420
|
+
if text == 0
|
421
|
+
@f.print "#{DIRECTIONS[dir]} is "
|
422
|
+
else
|
423
|
+
@f.print "#{OTHERDIRS[text]} is "
|
424
|
+
end
|
425
|
+
if e.type == Connection::CLOSED_DOOR or
|
426
|
+
e.type == Connection::LOCKED_DOOR
|
427
|
+
@f.print get_door_tag(e)
|
428
|
+
else
|
429
|
+
@f.print get_tag(b)
|
430
|
+
end
|
431
|
+
@f.puts '.'
|
432
|
+
}
|
433
|
+
objects(r)
|
434
|
+
end
|
435
|
+
|
436
|
+
def section(sect, idx)
|
437
|
+
name = sect.name
|
438
|
+
name = 'Unnamed' if name.to_s == ''
|
439
|
+
|
440
|
+
@f.puts
|
441
|
+
@f.puts "Section #{idx+1} - #{name}"
|
442
|
+
@f.puts
|
443
|
+
|
444
|
+
@f.puts
|
445
|
+
@f.puts "Part 1 - Room Descriptions"
|
446
|
+
@f.puts
|
447
|
+
sect.rooms.each { |r| room(r) }
|
448
|
+
@f.puts
|
449
|
+
@f.puts
|
450
|
+
|
451
|
+
@f.puts
|
452
|
+
@f.puts "Part 2 - Doors"
|
453
|
+
@f.puts
|
454
|
+
sect.connections.each { |e|
|
455
|
+
next if (e.type != Connection::LOCKED_DOOR and
|
456
|
+
e.type != Connection::CLOSED_DOOR)
|
457
|
+
door(e)
|
458
|
+
}
|
459
|
+
end
|
460
|
+
|
461
|
+
def start
|
462
|
+
@f = File.open("#@root.inform", "w")
|
463
|
+
story = @map.name
|
464
|
+
story = 'Untitled' if story == ''
|
465
|
+
today = Date.today
|
466
|
+
serial = today.strftime("%y%m%d")
|
467
|
+
|
468
|
+
@f.puts
|
469
|
+
@f.puts "\"#{story}\" by \"#{@map.creator}\""
|
470
|
+
@f.puts
|
471
|
+
@f.puts <<"EOF"
|
472
|
+
The story genre is "Unknown". The release number is 1.
|
473
|
+
The story headline is "An Interactive Fiction".
|
474
|
+
The story description is "".
|
475
|
+
The story creation year is #{today.year}.
|
476
|
+
|
477
|
+
|
478
|
+
Use full-length room descriptions.
|
479
|
+
|
480
|
+
EOF
|
481
|
+
|
482
|
+
@map.sections.each_with_index { |sect, idx|
|
483
|
+
section(sect, idx)
|
484
|
+
}
|
485
|
+
@f.close
|
486
|
+
end
|
487
|
+
|
488
|
+
def initialize(map, fileroot)
|
489
|
+
@tags = {}
|
490
|
+
@root = fileroot
|
491
|
+
@base = File.basename(@root)
|
492
|
+
@map = map
|
493
|
+
|
494
|
+
start
|
495
|
+
end
|
496
|
+
end
|