!% -~S
!% $OMIT_UNUSED_ROUTINES=1

! The very first lines of the main source code file for a game can contain compiler options, like the two lines above.
! -~S disables strict error checking. This is otherwise used in z5 and z8 games by default. While useful for debugging,
!   it adds ~10 KB to the story file size and it makes the game slower.
! $OMIT_UNUSED_ROUTINES=1 makes the compiler remove all routines which aren't used. This can save some space.

! This game is meant to be compiled with the Inform v6 compiler and the PunyInform library

Abbreviate ". ";
Abbreviate ", ";
Abbreviate " the ";
Abbreviate "You";
Abbreviate "The";
Abbreviate "thing";
Abbreviate "you";
Abbreviate "|    |";
Abbreviate "It's";
Abbreviate "dartboard";
Abbreviate "@@92";
Abbreviate "tion";
Abbreviate "logram kettlebell";
Abbreviate "'t se";
Abbreviate " th";
Abbreviate "ing";
Abbreviate " do";
Abbreviate " be";
Abbreviate " and";
Abbreviate " to";
Abbreviate " wa";
Abbreviate " ma";
Abbreviate " have";
Abbreviate "'s no";
Abbreviate " can";
Abbreviate " of";
Abbreviate "That";
Abbreviate "seems";
Abbreviate " it";
Abbreviate "_to/";
Abbreviate "ight";
Abbreviate "Paul";
Abbreviate "'t understand";
Abbreviate " some";
Abbreviate " on";
Abbreviate " pu";
Abbreviate "Inform";
Abbreviate " are";
Abbreviate " su";
Abbreviate " already";
Abbreviate " me";
Abbreviate "which";
Abbreviate " need";
Abbreviate " button";
Abbreviate " is no";
Abbreviate " mo";
Abbreviate " out";
Abbreviate " any";
Abbreviate "broom closet";
Abbreviate " with";
Abbreviate " we";
Abbreviate " co";
Abbreviate " for";
Abbreviate " lo";
Abbreviate " pr";
Abbreviate "her";
Abbreviate " ha";
Abbreviate " no";
Abbreviate "n't";
Abbreviate "e a";
Abbreviate "und";
Abbreviate " ki";
Abbreviate "ead";
Abbreviate "'s a";

Constant Story      "The job"; ! Change!
Constant Headline   "^A PunyJam #1 game by Fredrik Ramsberg.^"; ! Change if you like

Release 5;
Serial "210930";

Array UUID_ARRAY string "UUID://B41662E1-57A2-4045-B14C-F554A2B549FE//"; #Ifdef UUID_ARRAY; #Endif;

Constant STATUSLINE_TIME; Statusline time;

Constant NO_SCORE = 0;

! Uncomment to add optional features to PunyInform
!Constant DEBUG;
Constant CUSTOM_ABBREVIATIONS;
!Constant OPTIONAL_EXTENDED_METAVERBS;
Constant OPTIONAL_EXTENDED_VERBSET;
Constant OPTIONAL_PRINT_SCENERY_CONTENTS;
Constant OPTIONAL_SIMPLE_DOORS;
!Constant OPTIONAL_GUESS_MISSING_NOUN;
Constant OPTIONAL_MANUAL_SCOPE;
Constant OPTIONAL_MANUAL_REACTIVE;
Constant OPTIONAL_REACTIVE_PARSE_NAME;
Constant RUNTIME_ERRORS = 0; ! 0, 1 or 2. 0 = smallest file, 2 = most info

#Ifv5;
Constant OPTIONAL_PROVIDE_UNDO;
#Endif;

Constant INITIAL_LOCATION_VALUE = BroomCloset;
Constant AMUSING_PROVIDED;

Include "globals.h";

#Iffalse PUNYINFORM_MAJOR_VERSION == 3 && PUNYINFORM_MINOR_VERSION == 0;
       Message fatalerror "This is not the correct version of PunyInform for this
               program. Look at this line in the source code to see what version is
               required.";
#Endif;

Constant GS_ARRESTED = 3;

[ DeathMessage;
       if(deadflag == GS_ARRESTED)
               print "You have been arrested";
];

[ Amusing;
       "Hints you may or may not have seen that you're a diver and the entire game
               happens under water:^
       ^* You have a knife with a stainless steel blade, which is a good choice
               for a diver but not for a burglar.
       ^* ~examine me~, ~examine suit~ (or diving suit). The colour of your suit
               is normal for a diver, but not for a burglar.
       ^* Try to take off your suit. (With increasing water pressure comes the
               risk of ~nitrogen narcosis~, which makes it hard to think straight.)
       ^* The door is heavy to open.
       ^* The electricity doesn't work, and you're not surprised.
       ^* Examine the tables.
       ^* Type ~swim~, or ~swim east~.
       ^* Try examining, pushing or drinking the water.
       ^* Try smelling something.
       ^* Try throwing something at the dartboard.
       ^* You lose your consciousness if you take too long, since you run
               out of air.
       ^* The only reason the piece of paper has lasted is that it happens to be
               laminated.
       ^* If you drop the note or the piece of paper and go to the pub, the item
               will appear there after a while, due to the current.
       ^* If you load Paul's weight on the mat, it's not enough. The lock
               mechanism is flawed, so you can figure out the needed weight by
               reading the message you get when pushing down the door handle, and
               it's 95-99 kg (97 kg of iron under water weighs like
               80 kg at the surface.)
       ^* Standing on the mat doesn't change anything since you have neutral
               buoyancy, unless you are carrying weights of course.
       ";
];

Constant MSG_GO_CANT_GO "There's no obvious exit in that direction.";
Constant MSG_SWIM_DEFAULT "Well duh! Just say which direction you want to go.";
Constant MSG_SMELL_DEFAULT "You know you can't.";

Include "ext_menu.h";
Include "ext_quote_box.h";
Include "ext_cheap_scenery.h";

Include "puny.h";

Extend 'swim'
       * noun=ADirection -> Go;

Extend 'turn'
       * noun 'around'/'upsidedown' -> Turn;

Extend 'turn'
       * noun 'upside' 'down'    -> Turn
       * noun 'up' 'side' 'down' -> Turn
       * noun 'to' special       -> SetTo;

Verb 'flip' 'spin' = 'turn';

Extend 'pull'
       * 'out' noun -> Pull
       * noun 'out' -> Pull;

Extend 'look'
       * 'under' noun -> LookUnder;

Extend 'jump'
       * 'on' noun -> Enter;

Extend 'drop' first
       * multiexcept 'on'/'onto' noun -> PutOn;

Extend only 'push' 'press' first
       * 'down' noun -> Push
       * 'down' 'on' noun -> Push;

Verb meta 'help' 'hint' 'hints' 'about' 'instructions' 'commands' 'verbs'
       * -> Help;

Extend 'lock'
       * noun -> LockWithoutKey;

Extend 'unlock'
       * noun -> UnlockWithoutKey;

! Since there is only a single lockable object in the game, we can make
!  Lock/Unlock without key very simple.
[LockWithoutKeySub;
       "That can't be locked.";
];

[UnlockWithoutKeySub;
       "That can't be unlocked.";
];

[ HelpSub;
   DoMenu(HelpItems, HelpMenu, HelpInfo);
];

[ LookUnderSub;
       "You find nothing of interest.";
];


[ HelpItems;
   print "Choose an option:^^";
   print "      Instructions^";
   print "      About this game^";
   print "      Game credits^";
   print "      Hints^";
];

[ HelpMenu;
   switch(menu_item) {
   0: item_width=20; item_name="Help and Information"; return 4;
   1: item_width=12; item_name="Instructions";
   2: item_width=15; item_name="About this game";
   3: item_width=12; item_name="Game credits";
   4: item_width=5; item_name="Hints";
   }
];

[ HelpInfo;
   switch(menu_item) {
   1:
               "This is a text adventure, or an interactive fiction game. You
                       experience a story, where you play the protagonist. You tell the
                       game what you want to do by typing orders and the game tells you
                       what the result is. Some possible orders are ~go east~, ~open door~,
                       , ~examine note~, ~take the knife~ and ~put the knife in the
                       locker~.^^
                       If you have never played a game like this before, I
                       recommend you go to http://pr-if.org/doc/ and click on ~How
                       to play Interactive Fiction~. There's a handy card there which you can
                       keep open in your browser, or print and keep next to your computer.";
   2:
               "The Job is a short game, written for the PunyJam #1
                       game jam in 2021. The jam version was severely under-implemented and
                       under-tested, making the game pretty incomprehensible. This is a
                       post-jam release which is hopefully a bit better.";
   3:
               "The Job was created by Fredrik Ramsberg. It uses the PunyInform
                       library, created by Fredrik Ramsberg and Johan Berntsson. PunyInform
                       is based on the Inform 6 standard library and uses the Inform 6
                       programming language, both by Graham Nelson.^^
                       This game was betatested by Johan Berntsson, Rickard Nobel and
                       Gaston Noblia.^^
                       RetroFan made the font PXLfont, used in the Commodore 64,
                       Commodore 128, Commodore Plus/4 and MEGA65 versions of the game.^^
                       Many thanks to the people who contributed.";
       4:
               DoMenu(HintItems, HintMenu, HintInfo);
               return 2; ! This means "return to the previous menu"
   }
];

[ HintItems;
   print "There are hints provided on:^^";
   print "      The broom closet^";
   print "      The pub^";
   print "      The gym^";
   print "      The kitchen^";
   print "      The office^";
   print "      A room not mentioned above^";
];

[ HintMenu;
   switch(menu_item) {
   0: item_width=6; item_name="Hints"; return 6;
   1: item_width=16; item_name="The broom closet";
   2: item_width=7; item_name="The pub";
   3: item_width=7; item_name="The gym";
   4: item_width=11; item_name="The kitchen";
   5: item_width=10; item_name="The office";
   6: item_width=26; item_name="A room not mentioned above";
   }
];

[ NextHint _dummy;
#IfV5;
       print "^^N = next hint. ";
       @read_char -> _dummy;
       new_line;
       if(_dummy == 'n' or 'N') {new_line; rfalse; }
#IfNot;
       print "^^Type N + [ENTER] for the next hint: ";
       _dummy = 1;
       @sread buffer parse;
       if(buffer->1 == 'n') { new_line; rfalse; }
#EndIf;
];

[ HintInfo;
   switch(menu_item) {
   1:
               print "You may want to read the note...";
               if(NextHint()) rtrue;
               "But there's nothing you really have to do here.";
   2:
               "There's nothing you need to do in the pub.";
   3:
               "There's nothing you need to do in the gym.";
       4:
               "There's nothing you need to do in the kitchen.";
       5:
               print "There is one object here which can be manipulated to get you
                       closer to the necklace.";
               if(NextHint()) rtrue;
               print "It's the dartboard.";
               if(NextHint()) rtrue;
               print "Turn it.";
               if(NextHint()) rtrue;
               print "To progress further, press down on the handle.";
               if(NextHint()) rtrue;
               print "The handle is connected to the mat.";
               if(NextHint()) rtrue;
               print "You need to put a certain weight on the mat for the handle
                       to work.";
               if(NextHint()) rtrue;
               print "If you have the wrong weight, the handle can't be fully depressed.";
               if(NextHint()) rtrue;
               print "If you have tried a lot of different weights and you think it
                       fails in the same way every time, you haven't been paying attention.";
               if(NextHint()) rtrue;
               "You get different messages when pushing down the handle, depending
                       on if there's too little or too much weight on the mat.";
       6:
               print "Now you should have arrived at the safe.";
               if(NextHint()) rtrue;
               print "You set the dials to a four-digit combination using e.g.
                       ~set dials to 1234~. If it's the correct combination, the safe is
                       immediately unlocked.";
               if(NextHint()) rtrue;
               print "Paul was scared he might forget the combination.";
               if(NextHint()) rtrue;
               print "So he hid the combination in his office.";
               if(NextHint()) rtrue;
               print "Look under stuff.";
               if(NextHint()) rtrue;
               print "It may not look like a number at first.";
               if(NextHint()) rtrue;
               print "Maybe it depends on your perspective?";
               if(NextHint()) rtrue;
               print "Try turning it upside down!";
               if(NextHint()) rtrue;
               "You need to think old numbers here.";
   }
];




[ TotalLoad p_obj   _o _w;
       objectloop(_o in p_obj && _o provides weight)
               _w = _w + _o.weight;
       return _w;
];

Constant TEXT_PUB "Your friend's pub, where you used to hang out
       all the time. And now it has come to this. It's all so sad.";
Constant TEXT_STOOL "They have black metal frames with reddish leather on top.";
Constant TEXT_TABLE "Their frames are made of solid wood. The table tops are
       made from some laminated board, all ruined now of course.";


Object LightSwitch "light switch"
       with
               name 'light' 'switch',
               describe [; rtrue; ],
               before [;
                       SwitchOn, SwitchOff, Push:
                               "You do. Nothing happens of course.";
               ],
               found_in [;
                       if(location ~= SecretRoom or Street) rtrue;
               ],
       has static;

Object Water "water"
       with
               name 'water',
               description "It's wet. There's lots of it.",
               before [;
                       Take, Remove:
                               "You could if you had a container to take it in, but it would
                                       still be utterly pointless.";
                       Turn, Push, Pull:
                               "You swirl your hand around a bit in the water.";
                       Drink:
                               "Actually, you do your best to avoid it.";
               ],
               found_in [; rtrue; ],
       has static scenery;

Object BroomCloset "Broom Closet"
       with
               description "You're in the rather dirty broom closet of The Red Anchor.
                       Various cleaning appliances line the walls. There's a pile of fabric
                       in a corner.",
               cheap_scenery
                       'broom' 'closet' "It's not a nice place to hang out."
                       'cleaning' 'appliances' "Miscellaneous tools which were used to
                               clean the pub.",
               e_to BroomClosetDoor;

Object -> PileOfFabric "pile of fabric"
       with
               name 'pile' 'of' 'fabric',
               before [;
                       Take:
                               "You decide against it. You know where to find the fabric,
                                       should you need it.";
               ],
       has scenery;

Object -> Note "note"
       with
               name 'note',
               initial "A note has been fixed to the wall with a knife.",
               description "Written with a broad pen is ~RETURN WITH THE NECKLACE,
                       OR DON'T RETURN!~ You're guessing Ricky wrote it.",
               after [;
                       Take:
                               if(Knife hasnt moved && self hasnt general) {
                                       ! Use the general attribute to say we've already pulled
                                       ! the note from the wall, so we don't print this twice.
                                       give self general;
                                       "The knife rips a long hole in the note as you pull the
                                               note from the wall.";
                               }
               ];

Object -> Knife "knife"
       with
               name 'knife',
               description [;
                       if(self hasnt general && self hasnt moved) {
                               give self general;
                               print "Hey, that looks a lot like your knife. It is your knife!";
                       } else
                               print "It's your trustly old knife.";
                       " Black handle, stainless steel blade, and just the perfect size.";
               ],
               describe [;
                       if(self hasnt moved) {
                               if(Note hasnt moved) {
                                       ! Knife and note haven't moved. Knife is mentioned in
                                       ! description of note
                                       rtrue;
                               }
                               ! The knife hasnt been moved but the note is gone.
                               "^The knife is still deeply embedded in the wall.";
                       }
                       ! The knife has been moved. Now it should just be described as a
                       ! regular object
                       rfalse;
               ],
               before [;
                       Pull:
                               if(self hasnt moved)
                                       <<Take self>>;
               ],
               after [;
                       Take:
                               if(Note hasnt moved && Note hasnt general) {
                                       move Note to player;
                                       update_moved = true;
                                       "You pull out the knife and get the note that's impaled
                                               on it.";
                               }
               ];

Object BroomClosetDoor "broom closet door"
       with
               react_before [;
                       if(action == ##Go && self hasnt open &&
                                       ((location == BroomCloset && selected_direction == e_to) ||
                                       (location == Pub && selected_direction == w_to))) {
                                               print "(first opening the door)^";
                                               keep_silent = true;
                                               <Open self>;
                                               keep_silent = false;
                                               if(self hasnt open) rtrue; ! Failed, don't proceed
                                               new_line;
                                       }
               ],
               after [;
                       Open:
                               "Opening the door is incredibly heavy at first, but
                                       gets a lot easier when there's a crack wide
                                       wide enough to see through.";
               ],
               parse_name [ w1 w2 w3;
                       w1 = NextWord(); w2 = NextWord(); w3 = NextWord();
                       if(w1 == 'broom' && w2 == 'closet' && w3 == 'door') return 3;
                       if(w1 == 'closet' && w2 == 'door') return 2;
                       if(w1 == 'door') return 1;
               ],
               when_open [;
                       if(self in BroomCloset)
                               "You can see the pub through the door opening to the east.";
                       "The door to the west is open, revealing a broom closet.";
               ],
               when_closed [;
                       if(self in BroomCloset)
                               "The pub lies beyond the closed door to the east.";
                       "There's a closed door to the west.";
               ],
               found_in BroomCloset Pub,
               door_dir (e_to) (w_to),
       has static door openable reactive;

Object Pub "Pub"
       with
               description "This used to be your local watering hole. Paul, the owner,
                       is also a good friend of yours. A number of high tables are screwed
                       to the walls, with bar stools in front of them. The oak counter
                       sits along the north wall. There's no activity behind the counter
                       tonight though. The light switch is next to the counter, right
                       beside the doorway to the kitchen. The gym lies to the east, while
                       the exit is to the south.",
               cheap_scenery
                       'pub' 'room' TEXT_PUB
                       'red' 'anchor' TEXT_PUB
                       1 'stool' TEXT_STOOL
                       'bar' 'stools' TEXT_STOOL
                       1 'table' TEXT_TABLE
                       'high' 'tables' TEXT_TABLE
                       'oak' 'counter' "Such a beautiful counter. You haven't really stopped to admire it before.",
               w_to BroomClosetDoor,
               e_to Gym,
               n_to Kitchen,
               s_to [;
                       if(Necklace in player)
                               return Street;
                       "You don't dare to go back without the necklace.";
               ];

Class KettleBell
       with
#IfV5;
               name 'kettle' 'bell' 'bells//p' 'kettlebell' 'kg' 'kilo' 'kilos' 'kilogram' 'kilograms',
#IfNot;
               parse_name [ _i;
                       while(NextWord() == 'kettle' or 'bell' or 'bells//p'
                               or 'kg' or 'kilo' or 'kilos' or 'kilogram'
                               or self.&name-->0 or self.&name-->1) _i++;
                       return _i;
               ],
#EndIf;
               weight 0,
               description "You know the kind. Made of iron, with a layer of a rubbery
                       material on it.",
               before [;
                       Take, Remove:
                               if(TotalLoad(player) + self.weight > 50)
                                       "Your load is too heavy.";
               ],
       has reactive;

Object Gym "Gym"
       with
               description "The Gym is really only big enough for one or two people.
                       You remember when Paul threw out all the old stuff that had been
                       tucked away here over the years and converted the room to a gym,
                       to assist in his weight loss. The regulars could use it too, and
                       you for one often did just that. The pub lies to the west.",
               cheap_scenery
                       'gym' 'room' "This room used to smell of sweat. Not now, of
                               course.",
               w_to Pub;

Object -> Locker "locker"
       with
               name 'big' 'steel' 'locker',
               when_open [;
                       print "A black locker stands in a corner. ";
                       <Search self>;
               ],
               when_closed "A closed black locker stands in a corner.",
               description "It's a big steel locker.",
       has static container openable;

KettleBell -> -> Bell2 "two kilogram kettlebell"
       with
               weight 2,
               name '2//' 'two';

KettleBell -> -> Bell5 "five kilogram kettlebell"
       with
               weight 5,
               name '5//' 'five';

KettleBell -> -> Bell10 "ten kilogram kettlebell"
       with
               weight 10,
               name '10' 'ten';

KettleBell -> -> Bell20 "twenty kilogram kettlebell"
       with
               weight 20,
               name '20' 'twenty';

KettleBell -> -> Bell30 "thirty kilogram kettlebell"
       with
               weight 30,
               name '30' 'thirty';

KettleBell -> -> Bell40 "forty kilogram kettlebell"
       with
               weight 40,
               name '40' 'forty';

KettleBell -> -> Bell50 "fifty kilogram kettlebell"
       with
               weight 50,
               name '50' 'fifty';

Object Kitchen "Kitchen"
       with
               description "Just the kind of kitchen you typically find in small pubs -
                       it has what's needed to serve a burger, fish'n chips and what not.
                       You get a glimpse of the office through the doorway to the west,
                       and the pub lies to the south.",
               cheap_scenery
                       'kitchen' 'room' "A bit worn, but not terribly so. Paul and his
                               staff always seemed to enjoy working here.",
               s_to Pub,
               w_to Office;

Object Office "Office"
       with
               name 'hatch' 'compartment' 'glue',
               description [;
                       print "You've been here a few times before, with Paul. There's a
                               big desk close to the west wall, and a heavy chair behind it.
                               There's a dartboard on the north wall, and a square black
                               rubber mat just in front of it. ";
                               if(DoorHandle has general)
                                       "There are doorways leading north and east.";
                               "A doorway leads east.";
               ],
               cheap_scenery
                       'office' 'room' "It's a neat and tidy office. At least you can see it
                               used to be.",
               e_to Kitchen,
               n_to [;
                       if(DoorHandle has general)
                               return SecretRoom;
                       return 0;
               ];

Object -> Desk "desk"
       with
               name 'big' 'desk',
               description "It's a quite impressive desk.",
               before [;
                       Push, Pull, Turn, Take:
                               "The desk is incredibly heavy. You can't move it at all.";
                       LookUnder:
                               if(CodeNote in nothing) {
                                       move CodeNote to player;
                                       scope_modified = true;
                                       update_moved = true;
                                       "Oh, you find a piece of paper attached with some sticky
                                               substance under the desk! You take it.";
                               }
               ],
       has static scenery supporter enterable;

Object -> -> Photo "photo"
       with
               name 'framed' 'frame' 'photo',
               description "It's a framed photo of Paul, you and some of the other
                       regulars at the pub. Paul looks like he just won a million dollars.
                       You remember the occasion - Paul wanted to celebrate reaching his
                       goal weight after losing forty kilograms, which was actually a
                       third of his original weight. That was six months ago, and he
                       hasn't gained a kilogram since.",
               before [;
                       Remove:
                               if(second == self)
                                       <<Open self>>;
                       Open:
                               "The frame seems to be sealed shut. Better not waste any more
                                       time on it.";

               ];

Object -> Chair "chair"
       with
               name 'heavy' 'chair',
               description "It's Paul's heavy, comfortable chair.",
       has static scenery supporter enterable;

Object -> Dartboard "dartboard"
       with
               name 'dartboard' 'dart' 'board',
               description "Standard dartboard, and of course it's mounted at the
                       correct height. Along the outer edge someone has written:
                       ~PROPRIETE DU CAPITAINE LOUI~",
               before [;
                       ThrownAt:
                               move noun to Office;
                               "Standing at the correct distance, you throw ",
                                       (the) noun, " but, as expected, you fail to hit the board.";
                       Search:
                               BlackMat.step_on();
                               "You find circles, numbers etc - the stuff you'd expect to find
                                       on a dartboard.";
                       Open, Close:
                               "You'd have to describe just how you mean to do that.";
                       Turn:
                               BlackMat.step_on();
                               if(self hasnt general) {
                                       give self general;
                                       move DoorHandle to Office;
                                       BlackMat.number = 100; ! Don't print any more clue messages
                                       scope_modified = true;
                                       "As you turn the dartboard ninety degrees counterclockwise,
                                               a small hatch you hadn't noticed, set in the wall just
                                               below the dartboard, opens, revealing a door handle!";
                               }
                               "The dartboard seems to be stuck in its turned position.";
                       Pull, Take:
                               BlackMat.step_on();
                               "The dartboard flexes a little. Weirdly enough, it feels like
                                       it's only attached to the wall at the very center of the
                                       board.";
                       Push:
                               BlackMat.step_on();
                               "The dartboard doesn't move at all.";
               ],
       has static scenery;

Object -> BlackMat "black mat"
       with
               name 'square' 'black' 'rubber' 'mat',
               description [;
                       if(Dartboard hasnt general && self.number < 3)
                               "A mat of a kind that's common below dartboards, to protect
                                       the floor.";
                       <<Rub self>>;
               ],
               rattle_counter 0,
               rattle [ _r;
                       _r = self.rattle_counter++;
                       if(_r == 0)
                               ", and there's a faint metallic rattle, but you can't
                                       tell where it comes from.";
                       ", and there's that metallic rattle again.";
               ],
               before [;
                       Cut:
                               if(Knife in player)
                                       <<Attack self Knife>>;
                               "You don't have anything to cut it with.";
                       Attack:
                               if(second == Knife)
                                       "You make some cuts into the mat, but it stays firmly
                                               attached to the floor.";
                       Rub, Push, Pull, LookUnder, Take:
                               give self general;
                               "The mat seems glued to the floor, but also it moves a little when
                                       you tug at it with your hand. Or it's more like a piece of the
                                       floor is loose and the mat is glued to that piece.";
                       Enter:
                               if(player in self)
                                       <<Jump>>;
               ],
               react_before [;
                       Jump:
                               if(player in self) {
                                       print "The mat wiggles a bit";
                                       self.rattle();
                                       rtrue;
                               }
               ],
               after [;
                       Enter:
                               print "The mat wiggles a bit";
                               self.rattle();
                               rtrue;
                       Receive:
                               if(noun provides weight && noun.weight > 9) {
                                       print "The mat wiggles a bit";
                                       self.rattle();
                                       rtrue;
                               }
               ],
               number 0,
               step_on [ _step;
                       if(Dartboard has general) rtrue; ! The passage is already open
                       _step = ++self.number;
                       if(_step < 3) rtrue;
                       switch(_step) {
                       3:
                               if(self has general)
                                       "As you happen to put your foot on the black mat in
                                               front of the dartboard, you notice that the mat,
                                               or rather the mat and the
                                               piece of floor beneath it, move a little as you step
                                               on the mat.";
                               "As you happen to put your foot on the black mat in front of the
                                       dartboard, you could have sworn that the mat moved
                                       a little, as if it was on wheels or something. But
                                       surely you must have been mistaken.^";
                       5:
                               "There it is again! The mat moved a little, but if anything
                                       you think it sank into the floor, every so slightly. And
                                       some kind of noise came from the wall where the dartboard
                                       hangs.";
                       }
               ],
       has static scenery supporter enterable reactive;

Object DoorHandle "door handle"
       with
               name 'door' 'handle',
               initial "Just below the dartboard is a small compartment in the wall,
                       featuring a door handle.",
               description "Looks like a perfectly normal door handle. Like a lever
                       you press down on to open a door, only there's no door here.",
               before [ _w;
                       Take:
                               "It seems quite securely fixed to the wall. ";
                       Pull:
                               "It won't budge at all when you tug at it.";
                       Open, Push:
                               if(self hasnt general) {
                                       _w = TotalLoad(BlackMat); ! Ideal weigth is 97 kg (= 80 kg at surface)
                                       if(player in BlackMat) _w = _w + TotalLoad(player);
                                       if(_w < 95)
                                               "You can't push it down more than about a centimeter
                                                       before it stops and won't go any further.";
                                       if(_w > 99)
                                               "The door handle won't budge at all.";
                                       give self general;
                                       "As you push down on the handle, a large panel in the wall
                                               next to the dartboard slides aside. There is now an
                                               opening into a dark room to the north.";
                               }
                               "Nothing happens.";
               ],
       has static;

Object SecretRoom "Secret Room"
       with
               description "A small space, only about two by two meters. The walls
                       are black. A doorway leads south.",
               cheap_scenery 'wall' 'walls' "Looks painted. In fact, it looks like
                       someone who wasn't very good at painting painted it, perhaps
                       Paul himself.",
               s_to Office;

Object -> Safe "safe"
       with
               name 'safe',
               description "It's pretty big and must weigh a lot. It's probably
                       screwed to the floor or the wall as well.",
               when_open [;
                       print "There is an open safe at the north wall, with a set of dials
                               and a button on the door. ";
                       <Search self>;
               ],
               when_closed "A closed safe stands at the north wall. It has a set of dials
                       and a button on the door.",
               before [ _r;
                       UnlockWithoutKey:
                               if(self hasnt locked)
                                       "It doesn't seem to be locked.";
                               "You may need to use the dials and the button to do this.";
                       Unlock:
                               if(self has locked)
                                       "There's no keyhole. Maybe the dials and button have
                                               something to do with it.";
                       LockWithoutKey:
                               if(self has open)
                                       "The safe is currently open.";
                               if(self has locked)
                                       "The safe is already locked.";
                               give self locked;
                               while(_r == 0 or 1009)
                                       _r = random(9999);
                               Dials.entered = _r;
                               "Using the dials and the buttont, you somehow manage to lock the safe.";
                       Lock:
                               "The safe doesn't have a keyhole.";
               ],
               add_to_scope Dials Button,
       has static container openable lockable locked reactive;

Object -> -> Necklace "necklace"
       with
               name 'necklace',
               description "It's absolutely beautiful, and no doubt quite valuable.";

Object Dials "set of dials"
       with
               name 'set' 'of' 'dials' 'dial',
               entered 0,
               description [ _comb;
                       print "It's a set of four dials, each showing numbers from 0 to 9. They're currently set to ";
                       _comb = self.entered;
                       print _comb / 1000;
                       print (_comb % 1000) / 100;
                       print (_comb % 100) / 10;
                       print (_comb % 10), ".^";
               ],
               before [;
                       Turn, Push, Pull, Open:
                               "To unlock the safe, try e.g. ~set dials to 1234~.";
                       SetTo:
                               if(parsed_number < 0 || parsed_number > 9999)
                                       "The dials can be set to a number between 0 and 9999.";
                               self.entered = parsed_number;
                               print "You set the dials and press the button. ";
                               <<Push Button>>;
               ],
       has static;

Object Button "button"
       with
               name 'button',
               description "It's a heavy duty metal button that protrudes a good
                       centimeter from the door. It's placed just to the right of the
                       dial.",
               before [;
                       Push:
                               if(Dials.entered == 1009) {
                                       if(safe has locked) {
                                               give Safe ~locked;
                                               "A loud CLICK is heard from the safe.";
                                       }
                                       "The button can be fully depressed. Nothing happens.";
                               }
                               "The button can hardly be depressed at all.";
               ],
       has static;

Object Street "Street"
       with
               description "You are in the street just outside the Red Anchor. The
                       street leads east and west. You can't see very far, but you
                       can make out the outlines of the small church to the east and
                       the public library down the street to the west.",
               cheap_scenery
                       'small' 'church' "That's where you used to go to church, before.
                               It may not have looked like much on the outside, but it was
                               beautiful on the inside."
                       'public' 'library' "It was a great small town library really.
                               The staff were very knowledgable and keen on helping people
                               find what they wanted."
                       1 'pub' TEXT_PUB
                       'red' 'anchor' TEXT_PUB
                       1 'fish' "You can't see any fish right now.",
               number 0,
               each_turn [ _n;
                       _n = self.number++;
                       switch(_n) {
                       3:
                               "^A fish swims by.";
                       5:
                               "^You hear an engine revving up above.";
                       10:
                               deadflag = GS_ARRESTED;
                               "^The engine above revvs up and speeds off in the distance.
                                       Soon you're out of air and have to ascend. You are greeted
                                       by the police who pull you up into their boat.";
                       }
               ],
               before [;
                       Swim:
                               <<Go FAKE_U_OBJ>>;
               ],
               n_to Pub,
               u_to Boat,
               cant_go "You don't really have the time to look around now.
                       It's time to go.";

Object Boat "Boat"
       with
               description "As you reach the surface, the crew in the boat pull you out
                       of the water. Ricky and the other divers are already in the boat.
                       Ricky grabs the necklace, gives you a pat
                       on the back and starts the engines.

                       ^^You feel horrible about stealing the necklace belonging to
                       Paul's wife, but at the same time you know you were forced to
                       do it. Paul's been struggling with the insurance company over
                       the last weeks, ever since the dam burst and flooded this part
                       of town. You can only hope he gets fair compensation for his pub.

                       ^^You notice a police boat
                       approaching, but Ricky assures you they'll never catch up. With
                       roaring engines and lights out, you head off. It seems you have
                       made it.",
               after [;
                       deadflag = GS_WIN;
               ];

Array codenote_quote --> 4 26
       "   @@92  /    |    |    |   "
   "    @@92/     |    |    |   "
       "    /@@92     |    | /@@92 |   "
       "   /  @@92    |    |/  @@92|   ";

Array codenote_quote_flip --> 4 26
       "   |@@92  /|    |    @@92  /   "
       "   | @@92/ |    |     @@92/    "
       "   |    |    |     /@@92    "
       "   |    |    |    /  @@92   ";

Object CodeNote "piece of paper"
       with
               name 'laminated' 'piece' 'of' 'paper',
               orientation 0,
               description [ _x _i;
                       _i = 0;
                       _x = codenote_quote;
                       if(self.orientation)
                               _x = codenote_quote_flip;
                       print "It's a laminated piece of paper. Someone has
                               scrawled on it with a pen:";
#Ifv5;
                       new_line;
                       @read_char _i;
#Endif;
                       QuoteBox(_x, true);
               ],
               before [;
                       Turn:
                               self.orientation = 1 - self.orientation;
                               "You turn it around.";
               ];

Object Flashlight "flashlight"
       with
               name 'flashlight' 'lamp',
               description "It's your trusty flashlight. It has never failed you.",
               before [;
                       SwitchOff:
                               "You made sure the batteries were fully charged before
                                       leaving home. There is no need to conserve power.";
               ],
       has light switchable on;

Object Suit "suit"
       with
               parse_name [ _w1;
                       _w1 = NextWord();
                       if(_w1 == 'suit') return 1;
                       if(_w1 == 'dive' or 'diving' && NextWord() == 'suit') return 2;
               ],
               description "You've had it for years and you had another one just like
                       it before that. Fits you perfectly. It's bright orange, which may
                       not be perfect for this kind of job, but this is not the kind of
                       job you usually do either.",
               before [;
                       Push, Pull, Turn:
                               "You could play with your suit all day, but you have more
                                       pressing matters to deal with.";
                       Take, Remove, Disrobe:
                               "You've seen some guys lose it on the job due to
                                       the pressure, but you usually manage to think straight.
                                       You keep the suit on.";
               ]
       has reactive static worn;

Object Death
       with
               time_left 0,
               time_out [;
                       if(Necklace in player) {
                               if(player in Street) {
                                       print "^You suddenly feel you're running out of air, and you
                                               decide to ascend.^^";
                                       <<Go FAKE_U_OBJ>>;
                               } else {
                                       deadflag = GS_DEAD;
                                       "^You discover too late that your time is up. Your head
                                               grows dim and you can't figure out what to do. You won't
                                               make it out in time.";
                               }
                       }
                       deadflag = GS_DEAD;
                       "^You suddenly notice that you've run out of time, but you know you can't return
                               without the necklace. You ponder your options, but your head
                               keeps getting dimmer, until you start to lose consciousness.
                               A warm, calm feeling ensues.";
               ];

Object Current "current"
       with
               float_object [ p_obj _ceil _parent _dest;
                       if(p_obj hasnt moved || p_obj in Pub || random(100) > 25) rtrue;
                       _ceil = TouchCeiling(p_obj);
                       if(_ceil == location) rtrue; ! Don't move while the player watches
                       if(_ceil == BroomCloset && BroomClosetDoor has open)
                               _dest = Pub;
                       if(_ceil == Kitchen or Gym)
                               _dest = Pub;
                       if(_ceil == Office)
                               _dest = Kitchen;
                       if(_ceil == SecretRoom)
                               _dest = Office;
                       if(_dest) {
                               _parent = parent(p_obj);
                               if(_parent ~= _ceil)
                                       move p_obj to parent(_parent);
                               else
                                       move p_obj to _dest;
                               scope_modified = true;
                       }
               ],
               daemon [;
                       if(~~IndirectlyContains(player, Note))
                               self.float_object(Note);
                       if(~~IndirectlyContains(player, CodeNote))
                               self.float_object(CodeNote);
               ];

[ PlayerAddToScope;
       PlaceInScope(Suit);
];

[Initialise _min;
       _min = 120;
       lookmode = 2;
       move Flashlight to player;
       player.add_to_scope = PlayerAddToScope;
       give player reactive;
       player.description = "Not too shabby. You've got the same old suit on,
               the one you always use for work.";
       StartTimer(Death, _min);
       StartDaemon(Current);
       SetTime(24 * 60 - _min, 1);
       print "^^Sure, your job has taken you on all sorts of trips and you've
               done some weird stuff, I mean you've got to pay the bills
               right? But tonight's assignment is one you didn't ask for.^^

               Business has
               been slow lately, and if it hadn't been for Ricky lending you some
               money a few months ago, you would've had to close the firm. When
               Ricky showed up at your house the other day, he wasn't exactly asking
               if you wanted the job - it was more of an order.^^

               And now you're here. You were busy searching in the broom closet,
               thinking you were alone,
               when you got a push from behind and fell over. Whoever pushed you
               also left a message...^^
               (Type HELP for game information.)^^
               ";
];