1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
281
282
283
284
285
286
|
// MiniScript (https://miniscript.org) example file,
// adapted from: http://rosettacode.org/wiki/RCRPG/MiniScript
pos = [0,0,0]
goal = [floor(rnd*10), floor(rnd*10), floor(3+rnd*5)]
dir = {} // key: direction name; value: [dx, dy, dz]
dirAbbrevs = {} // key: direction abbrevation; value: full name
dir.up = [0,0,1]
dir.down = [0,0,-1]
dir.north = [0,1,0]
dir.south = [0,-1,0]
dir.east = [1,0,0]
dir.west = [-1,0,0]
for k in dir.indexes
dirAbbrevs[k[0]] = k
end for
inverseDir = {"up":"down", "down":"up", "east":"west", "west":"east", "north":"south", "south":"north"}
descNum = function(count, noun)
if count == 1 then return "a " + noun
return str(count) + " " + noun + "s"
end function
descList = function(lst)
if lst.len == 0 then return ""
if lst.len == 1 then return lst[0]
if lst.len == 2 then return lst[0] + " and " + lst[1]
return lst[:-1].join(", ") + ", and " + lst[-1]
end function
pickAny = function(options)
lst = options.split(";")
return lst[rnd * lst.len]
end function
Contents = {}
Contents.ladders = 0
Contents.gold = 0
Contents.hammers = 0 // (note: a "sledge" is a sled or sleigh, not a sledgehammer)
Contents.desc = function(prefix, postfix=".")
s = []
if self.ladders > 0 then s.push descNum(self.ladders, "ladder")
if self.hammers > 0 then s.push descNum(self.hammers, "sledgehammer")
if self.gold > 0 then s.push descNum(self.gold, "gold coin")
if not s then return prefix + " nothing" + postfix
return prefix + " " + descList(s) + postfix
end function
Contents.initRandom = function()
self.ladders = (rnd < 0.3)
self.gold = ceil(rnd * 3) * (rnd < 0.1)
self.hammers = (rnd < 0.02)
end function
Contents.propName = function(obj)
if obj == "ladder" or obj == "ladders" then return "ladders"
if obj == "gold" or obj == "coin" or obj == "coins" then return "gold"
if obj[:6] == "hammer" or obj[:6] == "sledge" then return "hammers"
return ""
end function
Contents.hasAny = function(obj)
pname = Contents.propName(obj)
if pname == "" then return false
return self[pname] > 0
end function
Contents.withdraw = function(obj)
result = new Contents
if obj == "all" then
result.ladders = self.ladders
self.ladders = 0
result.hammers = self.hammers
self.hammers = 0
result.gold = self.gold
self.gold = 0
else
pname = Contents.propName(obj)
if self[pname] < 1 then return null
if obj[-1] == "s" then count = self[pname] else count = 1
self[pname] = self[pname] - count
result[pname] = count
end if
return result
end function
Contents.deposit = function(c)
self.ladders = self.ladders + c.ladders
self.hammers = self.hammers + c.hammers
self.gold = self.gold + c.gold
end function
inventory = new Contents
inventory.hammers = 1
Room = {}
Room.exits = {}
Room.color = ""
Room.init = function(pos)
self.contents = new Contents
self.contents.initRandom
if pos == goal then
self.color = "YOU FOUND IT! This is the mystical Room of MacGuffin!"
else if rnd < 0.5 then
// Give a hint about where the goal is.
opt = floor(rnd * 3)
if opt == 0 then
if goal[2] == pos[2] then
hint = "The MacGuffin lies on this level."
else if goal[2] > pos[2] then
hint = "The MacGuffin rests above."
else
hint = "The MacGuffin lies below."
end if
else if opt == 1 then
if goal[0] > pos[0] then
hint = "The MacGuffin lies to the east."
else if goal[0] < pos[0] then
hint = "The MacGuffin lies to the west."
else
hint = "The MacGuffin lies... <undecipherable>"
end if
else
if goal[1] > pos[1] then
hint = "The MacGuffin lies to the north."
else if goal[1] < pos[1] then
hint = "The MacGuffin lies to the south."
else
hint = "The MacGuffin lies... <undecipherable>"
end if
end if
self.color = "Scratched on the wall is a message: " + hint
else if rnd < 0.5 then
// Give some random color comment.
color = []
opt = floor(rnd * 3)
if opt == 1 then
color.push "You detect " + pickAny("a faint;an odd;a musty;a rotten;an unpleasant")
color.push pickAny("smell;odor;scent;stench") + " here."
else if opt == 2 then
color.push "You can hear a" + pickAny(" faint; quiet; soft; strange;n eerie")
color.push pickAny("dripping;scratching;scrabbling;whistling;moaning")
color.push pickAny("sound;noise") + " here."
else
color.push "The " + pickAny("walls here are;floor here is;ceiling of this room is")
color.push pickAny("smeared with;discolored by;marred by;covered with")
color.push pickAny("dried blood;cobwebs;scratches;gouges;scorch marks;soot;mineral deposits;bits of fur") + "."
end if
self.color = color.join
end if
self.exits = {}
end function
rooms = {} // key: STRING FORM of position; value: Room
getRoom = function(pos=null)
if pos == null then pos = globals.pos
key = str(pos)
if not rooms.hasIndex(key) then
rooms[key] = new Room
rooms[key].init pos
end if
return rooms[key]
end function
// Commands:
commands = {}
help = {}
commands.drop = function(obj)
items = inventory.withdraw(obj)
if items == null then
print "You don't have any " + obj + "."
else
getRoom.contents.deposit items
print items.desc("You drop")
end if
end function
help.drop = "Drops an item from your inventory into the room. Specify object name or ""all""."
commands.go = function(d)
oldRoom = getRoom
if dirAbbrevs.hasIndex(d) then d = dirAbbrevs[d]
if not dir then
print "Which direction?"
else if not dir.hasIndex(d) then
print "That's not a direction I recognize."
else if d == "up" and oldRoom.contents.ladders == 0 then
print "There is no ladder in this room to go up."
else
if not oldRoom.exits.hasIndex(d) then
if inventory.hammers < 1 then
print "There is no exit that way, and you don't have a sledgehammer."
return
end if
wall = "wall"
if d == "up" then wall = "ceiling"
if d == "down" then wall = "floor"
print "You bash the " + wall + " until you make a passage big enough to crawl through."
oldRoom.exits.push d
end if
delta = dir[d]
pos[0] = pos[0] + delta[0]
pos[1] = pos[1] + delta[1]
pos[2] = pos[2] + delta[2]
newRoom = getRoom
newRoom.exits.push inverseDir[d]
verb = "crawl"
if d == "up" then verb = "climb"
if d == "down" then
if newRoom.contents.ladders > 0 then verb = "climb" else verb = "drop"
end if
print "You " + verb + " " + d + "."
commands.look
if pos == goal then
print "You have recovered the MacGuffin and " + descNum(inventory.gold, "gold coin") + ". You win!"
globals.gameOver = true
end if
end if
end function
help.go = "Moves in the given direction, bashing open a passage if necessary."
commands.help = function(arg)
if aliases.hasIndex(arg) then arg = aliases[arg]
if help.hasIndex(arg) then
print arg + ": " + help[arg]
else
print "Available commands: " + descList(help.indexes.sort)
end if
end function
help.help = "Prints the help. Obviously."
commands.inventory = function(arg)
print inventory.desc("You have")
end function
help.inventory = "Lists the items you are carrying."
commands.look = function(arg)
print "You are at " + pos + "."
room = getRoom
if room.color != "" then print room.color
print room.contents.desc("You see", " here.")
exits = room.exits.indexes
if exits.len == 0 then
print "There are no exits."
else if room.exits.len == 1 then
print "There is a passage " + exits[0] + "."
else
print "There are passages " + descList(exits) + "."
end if
end function
help.look = "Prints a description of the room and its contents."
commands.quit = function(arg)
print "Quitter!"
globals.gameOver = true
end function
help.quit = "Quits the game."
commands.take = function(obj)
roomStuff = getRoom.contents
items = roomStuff.withdraw(obj)
if items == null then
print "You don't see any " + obj + " here."
else
inventory.deposit items
print items.desc("You take")
end if
end function
help.take = "Picks up an item in the room; specify item name, or ""all""."
// Command aliases:
aliases = {"i":"inventory", "inv":"inventory", "l":"look", "get":"take"}
// Main game loop
gameOver = false
commands.look
while not gameOver
cmd = input(">").split(" ", 2)
if cmd.len == 1 then cmd.push null
verb = cmd[0]
if aliases.hasIndex(verb) then verb = aliases[verb]
if commands.hasIndex(verb) then
f = commands[verb]
f cmd[1]
else if dirAbbrevs.hasIndex(verb) or dir.hasIndex(verb) then
commands.go verb
else
print "Invalid command. For help, enter: help"
end if
end while
|