!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! ANNOYOTRON V: ATROCITRON !! !! Copyright (c) 2016, Michael C. Martin !! Source published in 2023 under the BSD license, see README.txt !! !! If you're here because you're stuck, be warned. In the RATIONALE, !! I declared that "while I consider it fair to try to disassemble !! the game file to solve it, I intend the easiest way to make !! progress to be to play the game." Reading the source code is a !! MUCH easier way to make progress than playing the game, !! especially at the beginning and the end. If you're stuck early !! on, I'd suggest at least experimenting until you have some sense !! of what changes in each run and what doesn't, and at least some !! basic theory of what the "Impact" rating means and how it !! influences the game world. If you've already won a few times but !! haven't worked out how to win EVERY time, or are chasing down !! some last few elusive impacts, go for it; you probably already !! know what to search for and even if you don't you'll find it very !! quickly. !! !! If you're here because you found a message in the game that you !! can't find in the binary, or because you found a message IN THE !! BINARY that you do not expect to find in the game, you won't find !! either of those in here. Those are included from separate, !! procedurally generated Inform files and only referenced here. The !! external scripts that generate those Inform files are probably !! more useful to you than the ways they are used here. !! !! If you're here because you want to see how the world is !! randomized from run to run, this is the place, but the code isn't !! well commented, so good luck. Also there's a hilarious map bug !! still, and I haven't commented its location. Have fun! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Constant Story "Atrocitron"; Constant Headline "^An Interactive Puzzlebox by Michael C. Martin^(New players should type ABOUT.)^(Actually, I take that back; EVERYBODY should type ABOUT)^(Seriously, type ABOUT)^"; Constant MAX_SCORE 15; Release 1; Serial "161215"; ! Announce ourselves to the IFDB so that we can have a real library card Array uuid -> "UUID://CF258DD7-A030-4C89-A7EC-C01F1B870C0D//"; ! It's a secret to everybody Include ">easteregg.inf"; Include ">victory.inf"; Array permuter -> 256; Replace SaveSub; Replace RestoreSub; ! Assumes a modified parserm.h, which ifndef-guards the UNDO handling and converts score into impact Constant IMPACT__TX = "Impact: "; Constant DISABLE_UNDO; Include "Parser"; ! ALL doesn't include the sign until the player has shown they know they can take it; then it does. [ ChooseObjects obj code; if (code < 2) { if (obj has scenery) { return 2; } if (obj == sign && sign hasnt moved) { return 2; } return false; } return 3; ]; ! More score-to-impact translation Object LibraryMessages with before [ x1; Miscellany: if (lm_n == 50) { x1 = lm_o; print "Your environmental impact has just gone "; if (x1 > 0) print "up"; else { x1 = -x1; print "down"; } print " by ", (number) x1, " point"; if (x1 > 1) print "s"; rtrue; } NotifyOff: "Environmental impact report off."; NotifyOn: "Environmental impact report on."; Score: if (deadflag) { print "In that game your environmental impact was "; } else { print "Your environmental impact is "; } print score, " out of a possible ", MAX_SCORE, ", in ", turns, " turn"; if (turns ~= 1) print "s"; rtrue; ]; Include "VerbLib"; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! Utility routines, mostly for obfuscation hilarity !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! [ xor a b; return (b & (~a)) | ((~b) & a); ]; [ permute r n i j; permuter->0 = 0; for (i=1:ii = permuter->j; permuter->j = i; } ]; ! Two random number generators hiding in otherwise normal objects. The ! first is a xorshift PRNG from a fixed seed for deobfuscation, and ! the second forwards to the interpreter for "real" randomness. Both ! the deobfuscator and the world generator use permute, above, so this ! lets us share their behavior within a function. Object util "Utility Closet" with x 23103, y -29065, rnd [n t; t = xor(util.x, util.x*32); util.x = util.y; util.y = xor (util.y, ((util.y & $fffe)/ 2) & $7FFF); util.y = xor (util.y, xor(t, ((t & $FFF8)/8) & $1FFF)); return (util.y & $7FFF) % n; ] ; Object defrand with rnd [n; return random(n) - 1;]; [ DoVictory i j offset; for(i=0:i= VICTORY_REMAINDER) { break; } print (char) xor(victory->((permuter->j) + offset), util.rnd(256)); } offset = offset + 256; } ]; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! !! Game world !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Object Barrier "Grand Exit" with description "The hallway comes to an end here, with a very fancy-looking archway leading out to the south. The rest of this godforsaken place lies beyond a hallway to the north.", name 'hallway' 'archway', s_to [; if (sign.number ~= ticket.number) { "An invisible force repels you! It must not be your turn to exit yet."; } print "It's your turn to leave. What a fine figure you will cut, emerging into a world that probably makes far more sense than this one does!^^[Press a key to continue]^"; KeyCharPrimitive(); ClearScreen(); DoVictory(); deadflag = 2; rtrue; ], out_to [; <>; ], n_to room_1; Object -> sign "sign" with name 'large' 'sign' 'now' 'serving' 'number', initial [; print_ret "A large sign above the door reads ~Now Serving #", sign.number, ".~"; ], description [; print "The sign says ~Now Serving #", sign.number, ".~"; if (sign.number > ticket.number) { " Hopefully that counter wraps around."; } ""; ], invent [; if (inventory_stage == 2) { print " (bearing the number ", sign.number, ")"; } ], after [; Take: if (self hasnt general) { give self general; "Hey, that worked."; } ], number 0; Object ticket "ticket" with name 'ticket' 'number', description [; print_ret "The ticket has the number ", ticket.number, " prominently written on it."; ], invent [; if (inventory_stage == 2) { print " (bearing the number ", ticket.number, ")"; } ], before [; Drop, PutOn, Insert, ThrowAt: "That's your ticket out of here. You don't intend to let it out of your possession."; Eat: "This is your ticket out of here, not some kind of meal ticket."; ], number 0; Class Furniture with override_short_name "[UNINITIALIZED]", override_description "[UNINITIALIZED]"; Class Scatterable; Class MzRoom with number -1, short_name [furn; objectloop (furn && (furn ofclass Furniture)) { if (IndirectlyContains(self, furn)) { print (string) furn.override_short_name; rtrue; } } print (string) self.default_short_name; rtrue; ], description [furn; objectloop (furn && (furn ofclass Furniture)) { if (IndirectlyContains(self, furn)) { furn.override_description(); print_ret "^", (string) self.hallways; } } self.default_description(); print_ret "^", (string) self.hallways; ], hallways "[UNINITIALIZED]", default_short_name "[???]", default_description "[UNINITIALIZED]"; MzRoom room_1 with hallways "Hallways lead east and west. The archway to the grand exit lies to the south.", default_short_name "South Junction", default_description "You stand in a T-junction connecting three of this building's rooms.", w_to room_2, e_to room_3, s_to Barrier; MzRoom room_2 with hallways "A hallway leads east, while the room extends to the west and north.", default_short_name "Southwest Entrance", default_description "You are at the southern entrance to the western room.", w_to room_4, e_to room_1, n_to room_5, nw_to room_6; MzRoom room_3 with hallways "A hallway leads west, while the room extends to the east and north.", default_short_name "Southeast Entrance", default_description "You are at the southern entrance to the eastern room.", w_to room_1, e_to room_8, n_to room_9, ne_to room_10; MzRoom room_4 with hallways "The room extends to the north and east.", default_short_name "Southwest Corner", default_description "You're in the southwest corner of the building.", n_to room_6, e_to room_2, ne_to room_5; MzRoom room_5 with hallways "A hallway leads east, while the room extends to the south and west.", default_short_name "Northwest Entrance", default_description "You are at the northern entrance to the western room.", e_to room_7, s_to room_2, w_to room_6, sw_to room_4; MzRoom room_6 with hallways "The room extends to the south and east.", default_short_name "Northwest Corner", default_description "You're in the northwest corner of the building.", s_to room_4, e_to room_5, se_to room_2; MzRoom room_7 with hallways "Hallways lead east and west.", default_short_name "North Junction", default_description "This nondescript hallway connects three of the building's four rooms.", n_to annex_door, in_to annex_door, out_to annex_door, w_to room_5, e_to room_9; MzRoom room_8 with hallways "The room extends to the north and west.", default_short_name "Southeast Corner", default_description "You're in the southeast corner of the building.", n_to room_10, w_to room_3, nw_to room_5; MzRoom room_9 with hallways "A hallway leads west, while the room extends to the south and east.", default_short_name "Northeast Entrance", default_description "You are at the northern entrance to the eastern room.", w_to room_7, s_to room_3, e_to room_10, sw_to room_4; MzRoom room_10 with hallways "The room extends to the south and west.", default_short_name "Northeast Corner", default_description "You're in the northeast corner of the building.", s_to room_8, w_to room_9, sw_to room_3; Array roomlist --> room_1 room_2 room_3 room_4 room_5 room_6 room_7 room_8 room_9 room_10 annex; Class Solid class Scatterable, with name 'solid' 'solids//p' 'platonic' 'polyhedron' 'polyhedra//p' 'die' 'dice//p', num_sides 0, side_shape "[UNINITIALIZED]", description [; print_ret "A fine Platonic solid, perhaps six inches across. Each of its ", self.num_sides, " sides is a perfect ", (string) self.side_shape, "."; ], before [v; Roll: v = random(self.num_sides); print "You roll it like a giant d", self.num_sides, ", and get a blank face. These are, after all, featureless Platonic solids. You decide that you have rolled a"; if (v == 1 or self.num_sides) { print " natural"; } else if (v == 8 or 11 or 18) { print "n"; } print " ",v, "."; if (v == self.num_sides) { print " All right!"; } if (v == 1) { print " Bummer."; } print "^"; rtrue; ]; Object annex "Secluded Annex" with description "Something about this room feels... stable, somehow, in a way that the rest of this building does not.", in_to annex_door, out_to annex_door, s_to annex_door; Object -> annex_door "wooden door" with description "You think it's made of oak.", name 'door' 'wooden' 'oaken' 'oak' 'wood', when_closed [; if (self in room_7) "A wooden door adorns the north wall. It is closed."; "The wooden door back to the main hallway is to the south. It is closed."; ], when_open [; if (self in room_7) "A wooden door leads north into a small annex. It is open."; "A wooden door leads south back into the main area. It is open."; ], door_dir [; if (self in room_7) return n_to; return s_to; ], door_to [; if (self in room_7) return annex; return room_7; ], found_in annex room_7, react_before [; Go: if (noun.door_dir == self.door_dir()) return self.open_by_myself(); Enter: if (noun == self) return self.open_by_myself(); ], open_by_myself [ks; if (self has open) rfalse; print "(first opening ", (the) self, ")^"; ks = keep_silent; keep_silent = true; ; keep_silent = ks; if (self hasnt open) rtrue; ], after [; Open: sign.number = xor (sign.number, self.number); score = score - 1; rfalse; Close: sign.number = xor (sign.number, self.number); score = score + 1; rfalse; ], number 1, has static door open openable; Object poster "poster" class Scatterable, with name 'poster' 'movie' 'tagline' 'motto', description [; if (self hasnt general) { give self general; score = score + 1; sign.number = xor(sign.number, self.number); } "It seems to be an advertisement for a horror movie. The tagline blares ~Watch if you dare! WHAT IS SEEN CANNOT BE UNSEEN.~"; ], before [; Take: "It is glued to the wall."; Attack: "It is glued to the wall, and you can't get enough purchase to do any real damage."; ], initial "A poster adorns the wall here.", number 4; Object cheese "wedge of cheese" class Scatterable, with name 'cheese' 'sharp' 'cheddar' 'wedge', description "A wedge of sharp cheddar.", react_before [; Cut: print "The wedge of cheddar is not "; style underline; print "that"; style roman; " kind of ~sharp.~"; ], before [; Smell: "Smoky and just strong enough to make a sandwich interesting without overpowering it."; Taste: "Not bad, and it doesn't seem spoiled."; ], after [; Eat: score = score + 1; give self general; sign.number = xor(sign.number, self.number); "That might not have been the most sanitary thing to do, but it was certainly satisfying."; ], number 16, has edible; Object bed "bed" class Furniture, with name 'bed', initial "Much of this area is taken up by a full-sized bed.", description [; if (self has general) "It looks a bit rumpled after your nap."; else "It looks comfy."; ], override_short_name "Sleeping Nook", override_description "This area has been converted into an impromptu bedroom.", react_before [ks; Sleep: if (self hasnt general) { if (~~(player in self)) { print "(first getting into the bed)^"; ks = keep_silent; keep_silent = true; ; keep_silent = ks; } if (~~(player in self)) { rtrue; } give self general; score = score + 1; sign.number = xor(sign.number, self.number); print_ret "You have been at this for awhile, haven't you? You stretch out a bit and decide to maybe just rest your eyes a little, but before you know it you're waking up from an impromptu nap.^^You aren't completely sure how much time has passed. You suppose it doesn't matter too much, in the end."; } Go: if (player in self) { print "(first getting out of the bed)^"; ks = keep_silent; keep_silent = true; ; keep_silent = ks; rfalse; } ], number 128, has static supporter enterable; Object mirror class Furniture, with name 'mirror' 'blank.', short_name "mirror", initial [; print_ret (A) self, " hangs from the wall here."; ], override_short_name "Cosmetic Corner", override_description "This area seems designed to let people get dressed and made-up before performances.", description [; if (self has general) "It's cracked all across its surface."; "What a fine, adventurous figure you cut."; ], before [; Attack: if (self has general) "Your hands are unbloodied, and you'd just as soon keep it that way."; give self general; score = score + 1; sign.number = xor(sign.number, self.number); self.&name-->1 = 'cracked'; ! parser accepts 'cracked' once it is self.short_name = "cracked mirror"; "You put some impressive cracks in it, and miraculously manage to keep your hands intact."; Search: <>; ], number 1024, has static; Object button "button" class Scatterable, with name 'button' 'unlabeled', initial "There is a button on the wall here.", description [; print "The button has no label on it. "; if (self hasnt general) "It extends perhaps a centimeter from the wall."; "It is now flush with the wall after having been pressed."; ], before [; Push: if (self has general) "It has already been thoroughly pushed."; give self general; score = score + 1; sign.number = xor(sign.number, self.number); "You press the button and it locks into place with a firm ~click.~"; ], number 4096, has static; Object rope "rope" class Furniture, with name 'mysterious' 'rope' 'cord' 'tiny' 'hole', initial "A mysterious rope hangs down here out of a tiny hole in the ceiling.", description "You see nothing special about the rope beyond the mysterious fact of its existence.", override_short_name "Secret Belfry?", override_description "This region appears to control something up above. You're not sure what that could be.", react_before[; Tie: if (noun == rope || second == rope) { score = score + 1; sign.number = xor(sign.number, self.number); give self general; remove self; "As you try to manipulate the rope into position to get a knot, the rope goes slack, then taut, then retracts through the ceiling with sudden force."; } ], before [; Take, Pull, Swing: score = score + 1; sign.number = xor(sign.number, self.number); give self general; remove self; "You grab it and try to pull it down. It yields for a moment, and then retracts through the ceiling with sudden force."; Attack, Cut: score = score + 1; sign.number = xor(sign.number, self.number); give self general; remove self; "You grab it and try to rip it apart. It yields for a moment, and then retracts through the ceiling with sudden force."; Burn: score = score + 1; sign.number = xor(sign.number, self.number); give self general; remove self; "The mere heat of your intention ignites it, and soon there's nothing left. Pointlessly destructive, yes; plausibly irreversible, also yes; but you do feel you have satisfied some basic need."; ], number 16384; Object pail "pail" class Scatterable, with name 'pail' 'bucket', description [; if (crystals in self) "The pail is made of faded blue plastic. There's a layer of pale green crystals at the bottom, fine as sand."; "Faded blue plastic."; ], before [; Receive: "You have ample inventory space. You don't need to rely on some bucket to help you organize stuff."; LetGo: if (noun == crystals) { give self general; score = score + 1; sign.number = xor(sign.number, self.number); move crystals to real_location; "The crystals don't want to stay contained. No sooner do they leave the bucket do they end up scattered all about."; } Roll: print "You roll the pail around."; if (crystals in self) { give self general; score = score + 1; sign.number = xor(sign.number, self.number); move crystals to real_location; print " The crystals end up scattered everywhere."; } print "^"; rtrue; ], number 8192, has container open ~openable; Object crystals "crystals" pail with name 'crystals//p' 'pale' 'green' 'crystal', description [; if (self in pail) "There's a layer of pale green crystals at the bottom of the pail, fine as sand."; "The crystals are scattered all about now."; ], before [; Take: if (self notin pail) { "Cleaning up those crystals sounds suspiciously like work. No thanks."; } else { ! This is a workaround for a bug in Library 6/12, ! where LetGo isn't called on implicit takes out of ! containers. give pail general; score = score + 1; sign.number = xor(sign.number, pail.number); move crystals to real_location; "The crystals don't want to stay contained. No sooner do they leave the bucket do they end up scattered all about."; } Rub: if (self notin pail) { "Cleaning up those crystals sounds suspiciously like work. No thanks."; } Roll: if (self in pail) { give pail general; score = score + 1; sign.number = xor(sign.number, pail.number); move crystals to real_location; "You spill the crystals all over the room as if you were rolling a thousand tiny dice. Whee!"; } ], has transparent pluralname; Object siderotil "substance the crystals certainly are not" crystals with name 'siderotil', react_before [; if (noun == self || second == self) { remove self; "I have no idea what you are talking about."; } ], has scenery; Object fez "stylish fez" class Scatterable, with name 'stylish' 'fez' 'jaunty' 'tassel' 'tarboosh' 'hat', description "A well-made hat, with fine colors and a jaunty tassel. It seems to be your size.", after [; Wear: score = score + 1; sign.number = xor(sign.number, self.number); rfalse; Disrobe: score = score - 1; sign.number = xor(sign.number, self.number); rfalse; ], number 64, has clothing; Object television "television" class Furniture, with name 'television' 'set' 'tv' 'screen' 'crt' 'cathode' 'ray' 'tube', initial [; if (self has on) "A television set squats here, tuned to a display the color of the sky."; "A television set squats here."; ], override_short_name "Recreation Nook", override_description "This part of the building seems set up to let people relax.", description [; print "It's an aging cathode-ray model television. "; if (self has on) print "It doesn't seem to be recieving a picture; just various shades of bright blue."; print "^^The only obvious control is a power switch. "; ], before [; Take: "It's too unwieldy to lug around."; ], after [; SwitchOn: score = score + 1; sign.number = xor(sign.number, self.number); rfalse; SwitchOff: score = score - 1; sign.number = xor(sign.number, self.number); rfalse; ], number 2, has static switchable ~on; Object table "table" class Furniture, with name 'table' 'pattern' 'triangle' 'triangles//p' 'square' 'pentagon' 'mahogany' 'inscription', initial "A mahogany table lends this area a touch of class.", description "Inscribed on the table is an odd pattern. It's a series of three triangles, with a square between the first two and a pentagon between the last two.", override_short_name "Meeting Area", override_description "This part of the building is quite a bit fancier looking than the rest of it. Perhaps it was used to entertain more important guests.", after [; Receive, LetGo: if (noun ofclass Solid) { if (noun has general) { give noun ~general; score = score - 1; } else { give noun general; score = score + 1; } sign.number = xor(sign.number, noun.number); } rfalse; ], has static supporter; Object tetrahedron "tetrahedron" class Solid, with name 'tetrahedron' 'tetra' 'd4', num_sides 4, side_shape "equilateral triangle", number 32; Object cube "cube" class Solid, with name 'cube' 'hexahedron' 'hexa' 'hex' 'd6', num_sides 6, side_shape "square", number 256; Object octahedron "octahedron" class Solid, with name 'octahedron' 'octa' 'oct' 'diamond' 'd8', num_sides 8, side_shape "equilateral triangle", number 8; Object dodecahedron "dodecahedron" class Solid, with name 'dodecahedron' 'dodec' 'dodeca' 'd12', num_sides 12, side_shape "pentagon", number 512; Object icosahedron "icosahedron" class Solid, with name 'icosahedron' 'icos' 'icosa' 'd20', num_sides 20, side_shape "equilateral triangle", number 2048; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! New verbs and routines !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ! Keep track of if the player typed ABOUT, because we were insistent Global checked_about = false; [ AboutRant; if (~~checked_about) { print "Seriously, I "; style underline; print "told"; style roman; print " you to type ABOUT. "; } ]; [ SaveSub; AboutRant(); "Saving has been disabled. Enough of the puzzle is randomized that staying within one iteration will lead only to suffering."; ]; [ RestoreSub; AboutRant(); "You cannot RESTORE what was never SAVEd."; ]; [ UndoSub; AboutRant(); "You cannot UNDO in this game. Understand what you have wrought, and RESET THE PUZZLE if necessary."; ]; [ AboutSub; checked_about = true; print "Welcome to the Atrocitron! The Atrocitron is a non-traditional interactive fiction experience. In particular...^^The solution is different each time you play.^^The game can be rendered unwinnable without warning and without indication that you have done so.^^SAVE and UNDO are disabled.^^If the previous statements make you want to quit immediately and possibly burn down the webserver from which you got this file, please type RATIONALE first. This isn't a game with puzzles in it. The game itself "; style underline; print "is the puzzle"; style roman; ". Discover its workings, master the Atrocitron, and its secrets will be revealed.^^Type CREDITS for additional credits."; ]; [ RationaleSub; print "The short and informal version of the reason I did this was because I wanted to create a game designed not to be "; style underline; print "solved"; style roman; print " so much as "; style underline; print "broken"; style roman; print ". However, I also wanted to see if it was possible to break every tradition of playing fair with the player while still, in the end, actually playing fair.^^I suppose this is also as good a place as any to note that while I consider it fair to try to disassemble the game file to solve it, I intend the easiest way to make progress to be to play the game.^^More formally, "; style underline; print "(read, pretentiously)"; style roman; print " the Atrocitron is an experiment with the player's role in an interactive work. The usual way we talk about this is with the author and the player collaborating to produce a story within the author's guidelines. There is, however, a tradition of game performance that involves either ignoring or subverting the designer's play and narrative intent to do something entirely different - obviously evil runs that the game nevertheless scores as maximally saintly, glitch runs that do everything out of order, and so on.^^The Atrocitron is presented to the player as a prop and a plaything, and the player is invited to stay outside of it at several levels.^^This wound up delaying its release quite a bit as I realized that what I was really doing here was making a "; style underline; print "puzzle hunt artifact"; style roman; " instead of a deliberately awful work of IF. I've endeavored to make it worthwhile in that guise as well.^^Good luck!"; ]; [ CreditsSub; print "The Atrocitron has been perpetrated by Michael Martin, with the Inform 6 system by Graham Nelson and his many contributors.^^Dan Uznanski provided invaluable testing feedback on early versions of the game, helping to to get it into a much more consistent shape before I sent it to the rest of my testers: Dave Bushong, Audrey Carstensen, and Geordan Rosario.^^Special thanks, in alphabetical order, to Sean Barrett, Ade McT, Wesley Osam, and Ben Parrish. "; style underline; print "They know what they did."; style roman; print "^"; rtrue; ]; [ RollSub; print (The) noun, " "; if (noun has pluralname) { print "aren't"; } else { print "isn't"; } " something you can roll."; ]; ! Uncomment this function to allow for cheating ! [ WinSub; ! ticket.number = sign.number; ! "You cunningly alter your ticket number so that it is your turn right now. You cad!"; ! ]; [ Initialise i j diff mask; give player light; ! Suppress some unused variable warnings i = uuid->0; i = easteregg->0; i = victory->0; ! Create sign and ticket numbers and be sure they're different sign.number = random($7fff); permute(defrand, 15); diff = random(2)+6; ticket.number = sign.number; for (i=0:ii:++j,mask=mask*2); ticket.number = xor(ticket.number, mask); } ! Generate world permute(defrand, 10); for (i=0:i<10:++i) { mask = roomlist-->i; mask.number = permuter->i + 1; } permute(defrand, 11); i = 0; objectloop (mask && (mask ofclass Furniture)) { move mask to roomlist-->(permuter->i); i = i + 1; } objectloop (mask && (mask ofclass Scatterable)) { i = defrand.rnd(11); move mask to roomlist-->i; } objectloop (mask && (mask ofclass Solid)) { if (defrand.rnd(3) == 1) { move mask to table; } } lookmode = 2; ! VERBOSE notify_mode = 0; ! NOTIFY defaults to off location = Barrier; player.description = "You could be anyone, and quite possibly are."; move ticket to player; ]; [ UnseeSub; "What is seen cannot be unseen."; ]; [ DistunkSub; print_ret "You distunk ", (the) noun, " but distunking will not untunk a tunk."; ]; [ UntunkSub; "What is tunked cannot be untunked."; ]; !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! Grammar !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Include "Grammar"; Verb meta 'about' * -> About; Verb meta 'rationale' * -> Rationale; Verb meta 'reset' * -> Restart * 'the' 'puzzle' -> Restart * 'puzzle' -> Restart; Verb meta 'credits' * -> Credits; Extend only 'undo' first * -> Undo; ! Verb meta 'win' * -> Win; ! Verb meta 'cheat' * -> Win; Verb 'unsee' 'unexamine' * noun -> Unsee; Verb 'unlook' * -> Unsee * 'at' noun -> Unsee; Verb 'distunk' * noun -> Distunk; Verb 'untunk' * noun -> Untunk; Verb 'roll' * multiexcept -> Roll; Verb meta 'impact' * -> Score; ! Because of the nature of the game world, we want to check 'put on' ! before 'put in'. Extend 'put' first * multiexcept 'on'/'onto' noun -> PutOn; Verb 'place' = 'put'; Verb 'rip' 'tear' = 'attack'; ! until it is done