!-------------------------------------------------------------------------
! lloyd.inf -- A component of the Inform Port of Ditch Day Drifter
! 
! The file contains the source code for Lloyd, the friendly insurance
! robot and his insurance policy.
! -------------------------------------------------------------------------
! -------------------------------------------------------------------------
!
! -- Table of Contents --
!
! LLOYD (7)
!
!  status property (N)
!  Lloyd's status constants (O)
!
!   Lloyd (7.1)
!    attributes, parse_name (7.1a)
!    status (7.1b)
!    description (7.1c)
!    describe (7.1d)
!    daemon (7.1e)
!    orders (7.1f)
!    life (7.1g)
!    act (7.1h)
!    react_before (7.1i)
!    greet (7.1j)
!     insurance policy (7.1.1)
!     five-dollar bill (7.1.2)
!
! -------------------------------------------------------------------------

! (7) LLOYD

! (N) status property

Property status alias number;

! (O) Lloyd's status constants

Constant not_encountered 0;
Constant selling_insurance 1;
Constant following_you 2;

! (7.1) Lloyd

Object lloyd "Lloyd" InsuranceOffice 

 ! (7.1a)
 ! Lloyd is transparent so that the player can see the policy that
 ! he is offering.
 has proper transparent animate ! has general if he has already done 
                                ! something interesting this turn, and no
                                ! more unimportant messages from Lloyd should 
                                ! be printed.
 with 
  parse_name [
    wd num_matched;

    wd=NextWord();
    while (wd == 'lloyd' or 'friendly' or 
      'insurance' or 'robot' or 'officer' or 'polyester' or 'suit') {
      ! Match "insurance robot" or "insurance officer" but not "insurance",
      ! which probably refers to the insurance policy. This fixes a bug
      if (wd == 'insurance') {
        if (NextWord() == 'robot' or 'officer') num_matched=num_matched+2;
        else return num_matched;
      }
      else {
        num_matched++; wd=NextWord(); }
    }
    return num_matched;
  ],

  ! (7.1b)
  ! Lloyd exists in three states, the first of which is that you haven't
  ! met him yet.
  status not_encountered,

  ! (7.1c)
  ! The description is only printed when the player examines him.
  description
   "Lloyd the Friendly Insurance Robot is a strange combination of the
   traditional metallic robot and an insurance salesman; over his bulky
   metal frame is a polyester suit.",

  ! (7.1d)
  ! The describe property is called any time that Lloyd is in the room when
  ! a ##Look action occurs.
  describe [; 
     new_line;
     if (self.status == selling_insurance)
       "Lloyd is here, offering you an insurance policy for only one
       dollar.";
     else
       "Lloyd the Friendly Insurance Robot is here.";
  ],

  ! (7.1e)
  ! Once Lloyd's daemon is started (by his life routine, below), it runs
  ! every turn, even if Lloyd is not currently in scope. Thus, it has to be
  ! careful not to print any text unless Lloyd is in the same room as the
  ! player. That isn't a big concern In Ditch Day, because Lloyd is 
  ! dogged about following the player around after his daemon is started.
  daemon [ self_loc player_loc; 
     switch (self.status) {
       selling_insurance:

         ! If Lloyd has already acted this turn, don't do anything except
         ! unset his general attribute.
         if (self has general) { give self ~general; return; }

         ! If Lloyd isn't in scope, don't do anything.
         if (~~ TestScope(self)) return;

         ! daemon routines have to remember to print one (and only one) new-
         ! line character before printing any text. It is also good style
         ! to print another one before returning.
         new_line;
         switch (random(5)) {
           1: "Lloyd waits patiently for you to make up your mind about the
               insurance policy.";
           2: "Lloyd watches you expectantly, hoping you will buy the
               insurance policy.";
           3: "Lloyd shows you the insurance policy again. ~Only a dollar,~
               he says.";
           4: "Lloyd looks at you intently. ~What can I do to make you buy
               this insurance policy right now?~ he asks rhetorically.";
           5: "Lloyd reviews the policy to make sure it looks just right.";
         }
       following_you:

         ! These values will be used many times below, but not changed.
         ! So evaluate once, and use multiple times.
         self_loc=parent(self);
         player_loc=parent(player);

         ! Lloyd is in the same room with the player, so just do some
         ! random thing (unless it's a dark room... see below.) 
         if (self_loc == player_loc || player_loc == bed) {
           if (self has general) { give self ~general; return; }

           ! Saves me the trouble of sticking a "^" in front of every
           ! string, below.
           new_line;

           if (OffersLight(real_location) == 0) {
             ! We're in the dark here...
             if (location == thedark) "You can hear Lloyd bumbling 
               mechanically about in the darkness.";
             ! The player just turned out the lights...
             else "In the dark, Lloyd immediately runs into something. 
               ~Thanks a lot!~ he calls. ~That's sure to leave a scuff
               mark.";
           }
           ! The player just turned on the lights...
           else if (location == thedark) "Lloyd whirrs a mechanical sigh of
             relief. ~Thank goodness that's over,~ he says. ~My 'darkness'
             programming got accidentally erased last week during an awesome
             insurance seminar.~";

           switch (random(5)) {
             1: "Lloyd watches attentively to make sure you don't hurt
                 yourself.";
             2: "Lloyd hums one of his favorite insurance songs.";
             3: "Lloyd gets out some actuarial tables and does some
                 computations.";
             4: "Lloyd looks through his papers.";
             5: "Lloyd checks the area to make sure it's safe.";
           }
         }

         ! The following else-if structure prints special messages for
         ! certain movement situations. For instance, if a player climbs up
         ! the rope Lloyd should also scramble up the rope.
         else {
           new_line;
           if (player_loc == railcar)
             print "Lloyd hops into the rail car, showing remarkable agility
               for such a large mechanical device.";
           else if (self_loc == railcar)
             print "Lloyd hops out of the rail car.";
           else if (self_loc == PitBottom && player_loc == PitTop)
             print "Amazingly, Lloyd scrambles up the rope and joins you.";
           else if (self_loc == PitTop && player_loc == PitBottom)
             print "Lloyd descends smoothly down the rope and joins you.";
           else if ( (self_loc == Tunnel12 && player_loc == Tunnel7) ||
                     (self_loc == Tunnel7 && player_loc == Tunnel12))
             print "Somehow, Lloyd manages to squeeze through the crawl.";

           ! Lloyd has a few interesting reactions to stuff lying around
           ! Ditch Day. The general attribute of an apposite object is
           ! used to make sure Lloyd only reacts once to each situation. 
           else if (player_loc == Quad && Quad hasnt general) {
             give Quad general;
             print "Lloyd follows you. When he sees the apparent radioactive
               waste spill, he is quite alarmed. After a moment, though, he
               deduces that the spill is a staged part of the Ditch Day
               festivities, and he calms down.";
           }
           else if (player_loc == Storage && Storage hasnt general) {
             give Storage general;
             print "Lloyd enters the storage room. Upon seeing the guard, he
               rolls over and starts giving his insurance pitch. After a
               moment, he notices the guard is unconscious. ~It's just as
               well,~ he confides. ~Security work is awfully risky, and his
               rates would have been quite high.~";
           }
           else if (location == thedark) 
             print "Lloyd blunders in after you. ~Hey! Who turned out the 
               lights?~";
           else if (player_loc == ExplosiveLab)
             print "~Explosive Lab!~ blurts Lloyd, rolling into the room. 
               ~Erm, let's not tarry.~";
           else print "Lloyd follows you.";
           move self to player_loc;
           new_line;
           rtrue;
         }
       ! This code should never be reached.
       default:
         "Lloyd looks confused and insecure. Apparently his programming
         doesn't cover this situation.";
     }
  ],

  ! (7.1f)
  ! Lloyd, despite being amiable, is uncooperative.
  orders [; 
     Give:
       if (noun == policy && 
           second == player && self.status == selling_insurance) {
         give self general; 
         "~You have to pay for it first,~ Lloyd explains."; 
       }

     ! Let not understood words pass through. They will be intercepted by
     ! the "##Answer" life rule, later on.
     NotUnderStood: rfalse; 

     ! Reroute the order "Lloyd, hello" to a greeting.
     Hello:
       return self.greet();
     default:
       give self general;
       "~I'm sorry, that's not in your policy.~";
  ],
  ! (7.1g)
  life [; 
    Answer:
      if (noun == 'hello' or 'hi' or 'greetings' or 'salutations')
        return self.greet();
      "~I'm sorry,~ says Lloyd. ~Human phrasing is often difficult for me to
      comprehend. After all, I'm not AI complete.~";
    Ask:
      give self general;
      switch (second) {
        'policy': 
          "~Your policy perfectly fits your needs, according to my
          calculations,~ Lloyd says. ~I'm afraid it's much too
          complicated to go into any detail right now, but you have
          my assurances that you won't be disappointed.~";
        default: 
          "~I'm sorry,~ says Lloyd. ~Human phrasing is often difficult for me
          to comprehend. After all, I'm not AI complete.~";
      }
    Attack:
      give self general;
      if (self.status == selling_insurance)
        "~Hey!~ shouts Lloyd. ~If you don't want the policy, you don't have to
        buy it. There's no reason to be belligerent.~";
      "~Careful,~ says Lloyd, worriedly. ~You might damage one of your
        heavily insured appendages on my shiny metallic exterior.~";
    Give:
      give self general;
      switch (noun) {
        five_dollars:
          "Lloyd looks at you, confused. ~I've already sold you all the
          insurance you need!~";
        one_dollar:

          ! See the pay grammar and actions ["verbs.inf":10.13]. If the
          ! player indicated what they are paying for, it will be saved in
          ! the 'buy_obj' global variable. Lloyd can check it, and print a
          ! refusal if the player tries to buy anything but the policy. If
          ! it is blank, Lloyd assumes you are buying the policy.
          if (buy_obj == self) "~I'm not for sale,~ says Lloyd.";
          if (buy_obj ~= 0 && buy_obj ~= policy) {
            print "~I'm not selling ";
            ThatOrThose(buy_obj);
            ",~ explains Lloyd.";
          }
          ! After you buy the policy, Lloyd follows you around.
          self.status=following_you;
          remove one_dollar;
          move policy to player;
          "Lloyd graciously accepts the payment, and hands you a copy
          of your policy. ~You might wonder how we keep costs so low,~
          Lloyd says. ~It's simple; we're highly automated, which keeps
          labor costs low; I run the whole company, which keeps the
          bureaucratic overhead low; and, most importantly, I follow you
          everywhere you go for the duration of the policy, ensuring that
          you're paid on the spot should anything happen, which means we
          don't have to waste money investigating claims!~";
        darbcard:
          ! Give the player a 'good try' response if they try to buy the
          ! policy with the DarbCard.
          if (self.status == selling_insurance)
            "Lloyd looks at you apologetically. ~So sorry, I must insist
            on cash,~ he says.";
          else "Lloyd doesn't appear interested.";
        default:
          "Lloyd doesn't appear interested.";
      }
    Kiss:
      give self general;
      if (self.status == following_you)
        "~That definitely isn't in your policy,~ says Lloyd, fending you off.";
      "~Er, okay, if it will help you make up your mind to buy this policy,~
      says Lloyd, shrugging his metal shoulders.^^Kissing a robot doesn't turn
      out as exciting as might have hoped.";
    Show:
      give self general;
      switch (noun) {
        policy: "~Insurance is truly fascinating,~ says Lloyd.";
        one_dollar:
          if (self.status == selling_insurance) "Lloyd looks at it
            eagerly. ~Yes, that will do nicely,~ he explains.";
        five_dollars: "~Oh, yes,~ he says excitedly. ~Your policy will make
          you a rich man someday, I'm sure.~";
        flask, original_ln, bottled_ln:
          "~That stuff looks dangerous,~ warns Lloyd. ~I hope you know
          what you're doing.~";
        bottle:
          if (parent(bottled_ln) == bottle && bottle hasnt open) "~Get rid of 
            that thing!~ exclaims Lloyd.";
      }
  ],

! (7.1h)
! -------------------------------------------------------------------------
! Lloyd's act property is never called by the parser. It is called by code
! in various objects scattered throughout the game, with an apposite object
! for the argument. These are often reactions that would have been
! impractical to code with a react_before or react_after property.
! -------------------------------------------------------------------------
  act [ obj;
     give self general;
     switch (obj) {
       
       ! Called when the bottle explodes in the player's vicinity.
       bottle:
         print "^^";
         if (self.status == following_you)
           print "I'm sure that Lloyd is even now paying out a big lump sum 
             for your early demise. However, that is of little use to you
             now.^";

       ! Called when bottle explodes in the safe and Lloyd is present.
       bank_safe:
         print "^^Lloyd throws himself between you and the vault. ~Please be 
           careful!~ he admonishes. ~The payment for Accidental Death due
           to Explosion is enormous!~";

       ! Called after the strange machine button is pushed by the player.
       machine:
         if (five_dollars hasnt moved) {
           give five_dollars moved; ! the 'move' command doesn't give 'moved'.
           move five_dollars to player;
           print "^^Lloyd rolls over and looks at your thumb. ~That looks 
             awful,~ he says as you jump about, holding your thumb. Lloyd
             produces a thick pile of paper and starts leafing through it.
             ~Temporary loss of use of one thumb... ah, yes, here it is.
             That injury pays five dollars.~ Lloyd puts away his papers and
             produces a crisp new five dollar bill, which you accept (with
             your other hand).";
         }
         else
           print "^^Lloyd looks at you apologetically: ~I don't want to sound
             patronizing, but you knew it would do that. I'm afraid I can't
             accept a claim for that injury, as it was effectively
             self-inflicted.~ He looks at you sadly. ~I do sympathize. That
             must be quite painful,~ he understates.";

       ! This becomes part of the 'win' message. Called when the ship
       ! launches and Lloyd is present.
       launch_button:
         print "^^Lloyd heads for the door. ~Sorry,~ he says. ~I can't
           go with you. Your policy specifically excludes coverage
           during missions in deep space, and, frankly, it's too risky
           for my tastes. Besides, I don't appear in 'Deep Space
           Drifter.'~ Lloyd waves goodbye, and rolls out of the
           spaceship.";

       ! Called by the description property of the insurance office.
       InsuranceOffice:
         self.status=selling_insurance;
         StartDaemon(self);
         print "^^As you walk into the office, a large metallic robot--very
           much like the traditional sci-fi film robot, but wearing a dark
           polyester business suit--zips up to you. ~Hi, I'm Lloyd the
           Friendly Insurance Robot,~ he says in a mechanical British
           accent. ~You look like you could use some insurance! Here, let
           me prepare a policy for you.~^^Lloyd scurries around the room,
           gathering papers and studying charts, occasionally zipping up
           next to you and measuring your height and other dimensions,
           making all kinds of notes, and generally scampering about. After
           a few minutes, he comes up to you, showing you a piece of
           paper.^^~I have the perfect policy for you. Just one dollar will
           buy you a hundred thousand worth of Insurance!~ He watches you
           anxiously."; 

       ! This code should never be reached.
       default: 
         print "^^Lloyd stares in a stupidly mechanical manner, not knowing 
           what he is supposed to be doing.";
     }
  ],
  ! (7.1i)
  react_before [; 

    ! Lloyd interprets a general ##Hello actions as if it were directed at
    ! him.
    Hello:
      return self.greet();
    Listen:
      ! In stock Inform, lloyd's react_before property isn't called in the
      ! dark. The InScope entry point ["entrypts.inf":8.3] forces Lloyd
      ! into scope in the dark.
      if (noun == 0 or self && location == thedark) {
        give self general;
        "It sounds like Lloyd is thinking dark thoughts.";
      }

    ! Lloyd will prevent a few dangerous acts, to help characterize him.
    default:
      if ((action == ##Drink && noun ofclass LiquidNitrogen 
            && location ~= thedark) || 
          (action == ##Enter && noun == pit) || 
          (noun == bed or pit && 
           action == ##JumpOn or ##JumpInto or ##JumpOver)) {
        give self general;
        "In sudden alarm, Lloyd stops you: ~You could get seriously
        injured pulling a stunt like that.~";
      }
  ],

  ! (7.1j)
  ! There are quite a few different ways for the player to say hello to
  ! lloyd, so, to avoid duplicating code, they all call this routine.
  !
  ! Here are all the possible ways:
  !
  ! 1. LLOYD, HELLO
  !   Results in an order to Lloyd to perform the ##Hello action.
  !
  ! 2. SAY HELLO TO LLOYD
  !   Results in the Answer action, and runs Lloyd's life routine with
  !   action set to ##Answer and noun set to 'hello'.
  !
  ! 3. HELLO
  !   Calls the ##Hello action.
  !
  ! The ##Hello action and grammar: ["verbs.inf":10.6].
  greet [;
    if (self.status == following_you) "Lloyd looks at you strangely for
      a moment, comes to some sort of conclusion about carbon-based life-forms,
      and finally makes a shrugging motion: ~Hi. Nice weather we've been
      having.~";
    else "~Hello,~ says Lloyd, ingratiatingly.";
  ],
;

! (7.1.1) insurance policy

Crawlable ->-> policy "policy"
 with 
  name 'insurance' 'policy',
  description [; 
     print "The policy lists the payment schedule for hundreds of
       types of injuries. The list is far too lengthy to go into in any
       detail here, but rest assured, ";
     if (self in lloyd)
       "it looks like an excellent deal.";
     else
       "you're highly satisfied with what you got for your dollar. You feel
       extremely well protected.";
  ],
;

! (7.1.2) five-dollar bill

Crawlable five_dollars "five-dollar bill" 
 with name 'fiver' '5//' 'five' 'dollar' 'dollars' 'five-dollar' 'bill' 'money',
;