! -------------------------------------------------------------------------
! misc.inf -- A component of the Inform Port of Ditch Day Drifter
!
! This file contains the source code for miscellaneous objects and routines
! that are general purpose, or didn't logically belong somewhere else.
! -------------------------------------------------------------------------
! -------------------------------------------------------------------------
! -- Table of Contents --
!
! MISC (12)
!   replacement player object (12.1)
!    attributes, number, orders (12.1a)
!    awake_time, hungry_time, each_turn (12.1b)
!   SilentAction (12.2)
!   IsNotHeldOrTaken (12.3)
!   ShowCont (12.4)
!   EasterEgg (12.5)
!   EmphasisStyleText (12.6)
!   NormalStyleText (12.7)
!
! -------------------------------------------------------------------------

! (12) MISC

! (12.1) replacement player object

! These are the number of turns the player can stay awake before becoming
! drowsy and the number of turns the player can go without eating before
! becoming hungry.
Constant SLEEP_LIMIT=600;
Constant STARVE_LIMIT=250;

Object person
 ! (12.1a)
 has proper animate transparent concealed
 with 
  number 0,
  orders [ 
    direction destination; 
    ! The player's orders routine will prevent movement between dark rooms.
    ! In a different game, a routine like this would have to check for doors, 
    ! but in this game I don't bother because there are no dark rooms with 
    ! doors in them.
    Go:
      if (location == thedark) {
        direction=noun.door_dir;

        ! My direction property routines (n_to, s_to, etc...) are written
        ! to expect one parameter. A '1' suppress printing and processing
        ! in those routines.
        !                                   |
        !                                   v
        destination=real_location.direction(1); 
        if (~~ OffersLight(destination)) ! If there is no light source...
          "You stumble around in the dark and don't get anywhere.";
      }
  ],
  ! (12.1b)
  awake_time 0, ! Number of turns since the player last slept. 
  hungry_time 0, ! Number of turns since the player last ate.

  ! The each_turn property of the player will handle sleeping and eating
  ! penalties. In this game, they can be severe penalties. However, it is
  ! extremely difficult to incur them because the turn limits are very
  ! high.
  each_turn [ 
    limit obj;
    self.awake_time++;
    limit=SLEEP_LIMIT;

    ! warnings don't start to appear until after time has expired.
    if (self.awake_time == limit or limit+10 or limit+20)
      print "^You're feeling a bit drowsy. You should find a comfortable place
        to sleep.^";
    else if (self.awake_time == limit+25 or limit+30)
      print "^You should really find someplace to sleep soon, or you'll 
        probably pass out from exhaustion.^";
    else if (self.awake_time >= limit+35) {
      self.awake_time=0;

      ! Sleeping in the bed saves you from dropping all your items.
      if (parent(player) == bed) {
        print "^You find yourself unable to stay awake any longer. 
          Fortunately you are on the bed, so you gently slip off into 
          unconsciousness.^^* * * *^^ You awake some time later, feeling 
          refreshed.^";
      }
      else {
        print "^You find yourself unable to stay awake any longer. You pass 
          out, falling to the ground.^^* * * *^^You awaken feeling somewhat 
          the worse for wear. You get up and dust yourself off.^";

        ! Dump the player's possessions.
        obj=child(player);
        while (obj ~= 0) {
          limit=sibling(obj);
          if (obj hasnt worn) move obj to parent(player);
          obj=limit;
        }
      }
    }

    self.hungry_time++;

    limit=STARVE_LIMIT; 

    if (self.hungry_time == limit or limit+5 or limit+10)
    print "^You're feeling a bit peckish. Perhaps it would be a good time to 
      find something to eat.^";
    else if (self.hungry_time == limit+15 or limit+20 or limit+25)
    print "^You're feeling really hungry. You should find some food soon or
      you'll pass out from lack of nutrition.^";
    else if (self.hungry_time == limit+30 or limit+35)
    print "^You really can't go much longer without food.^";

    ! the penalty for poor nutrition is quite severe.
    else if (self.hungry_time >= limit+40) {
      deadflag=1;
      print "^You simply can't go on any longer without food. You perish
        from a combination of lack of nutrition and game design
        tradition.^";
    }
  ],
;

! (12.2)
! Call an action with keep_silent set to 1.
[ SilentAction act n s;
  ! Tell the Inform library to keep quiet for a moment...
  keep_silent=1;
  if (noun == 0) <(act)>;
  else if (second == 0) <(act) n>;
  else <(act) n s>;
  keep_silent=0;
];

! (12.3)
! This routine attempts to take an object if necessary. It returns false if
! the object is in the player's possession. It is used by action routines for
! implicit takes when the 'held' token is inconvenient. For instance, in
! this game, ##Take actions on liquids are redirected to their containers.
!
! Receives -> Any object
! Does -> attempts to takes the object if it is in scope.
! Returns -> False: if the object is carried by the player, or was picked
!                   up.
!            True: if the object isn't carried and couldn't be picked up.
[ IsNotHeldOrTaken obj;
  if (obj in player) rfalse;
  ! It is legal and useful to call this routine on an item that isn't in 
  ! scope. For instance, you can't close the plastic bottle unless the
  ! bottle cap ["surface.inf":1.1.3.1.1] is in scope.
  if (~~ TestScope(obj)) rtrue;
  print "(first taking ", (the) obj, ")^";
  SilentAction(##Take, obj);
  if (obj in player) rfalse;
  else rtrue;
];

! (12.4)
! Print the contents of containers and supporters: either a sentence saying
! it is empty, or what is on/in it. This routine prints no leading or
! trailing new-lines.
[ ShowCont obj;
    if (children(obj) == 0) print (The) obj, " is empty";
    else {
      if (obj has supporter) print "On";
      else print "In";
      print " ", (the) obj, " you can see ";
      WriteListFrom(child(obj),ENGLISH_BIT+FULLINV_BIT+RECURSE_BIT);
    }
    print ". ";
];

! (12.5)
[ EasterEgg;
  EmphasisStyleText();
  print "** ERROR **";
  NormalStyleText();
  "^^You have performed an idiotic action.^^A few milliseconds will pass
  while the computer laughs at you for 12,000,000,000 cycles.^^While we're
  waiting, I'll take this opportunity to thank those who made this port
  possible.^^First, I would like to thank Mike Roberts, who wrote this fine
  example game in the first place, and gave me permission to port it in the
  second place. Second, I would like to thank Graham Nelson, who wrote,
  supports, and regularly updates Inform. Third, thanks to the regulars of
  rec.arts.int-fiction, who provided me with inspiration. Last, thanks to
  Chris Markwyn who gave me the idea and got me started.";
];

! (12.6)
[ EmphasisStyleText;
  #ifdef TARGET_ZCODE;
  style bold;
  #ifnot; ! TARGET_GLULX


  ! Glulx doesn't allow  "style bold" because of the way that text styles
  ! are handled in Glk -- a Glk application leaves the determination of a
  ! font style for emphasis to the user. To switch to whatever font the
  ! user prefers for emphasis, you must use a Glk call.
  !
  ! The format of a Glk call in Glulx Inform is:
  !
  !   Glk(Glk_routine_code, arg1, arg2, ...);
  !
  ! You can find prototypes for all the Glk routines in Glk.h. The Glk
  ! routine codes can be found in the Glk spec. 
  !
  ! If this seems too difficult, John Cater has put together a nice
  ! header file galled infglk.h, which makes Glk calls easier by
  ! delcaring Inform routine wrappers for them. 
  !
  ! All this stuff is available from Andrew Plotkin's Glulx web-page:
  !
  ! http://www.eblong.com/zarfhome/glulx/index.html
  glk($0086, 1); ! glk_set_style(Emphasis_style);
  #endif;
];


! (12.7)
[ NormalStyleText;
  #ifdef TARGET_ZCODE;
  style roman;
  #ifnot; ! TARGET_GLULX
  glk($0086, 0); ! glk_set_style(Normal_style);
  #endif;
];