Follow

Follow is an extension by Kent Tessman that allows for multiple following NPCs (defaults to 8). This slightly-modified version (some Future Boy! -specific code has been commented out) follows the instructions dictated by its license.

A version of this is included with Roodylib.

Usage

Use the AddFollower and RemoveFollower routines to add characters to the characters-following array, and StartFollowing to turn it on (and StopFollowing to turn it off).

The code

!-————————————————————————–

  follow.h version 2.0

  Mechanisms for enabling NPCs to follow the player

  by Kent Tessman

  Updated for general usage by Jon Blask
  (See original at http://roody.gerynarsabode.org/follow.hug)

  [Original code also has a routine for counting followers,
  support for a follower-of-a-follower, and multimedia stuff- as
  they pertain to Future Boy!]

—————————————————————————! #ifclear _FOLLOW_H #set _FOLLOW_H

#ifset VERSIONS #message “Follow.h Version 2.0” #endif

constant MAX_FOLLOWERS 8

array follower_list[MAX_FOLLOWERS] array moved_follower[MAX_FOLLOWERS] attribute following global followers global following_paused

property follow_message ! for locations, a suffix such as ! “ you down the stairs.”

property disallow_follow ! return true if circumstances disallow ! following (for characters or locations)

property pause_following ! for NPCs

routine AddFollower(char) { if followers = MAX_FOLLOWERS or char is following return false follower_list[followers++] = char char is following return true }

routine RemoveFollower(char) { local i for (i=0; i<MAX_FOLLOWERS; i++) { if follower_list[i] = char { while (i < MAX_FOLLOWERS-2) { follower_list[i] = follower_list[i+1] i++ } follower_list[MAX_FOLLOWERS-1] = 0 followers– char is not following return } } }

!
StartFollowing and StopFollowing are just two “helper” routines so authors don’t need to remember that the following mechanism is handled by a daemon (and therefore needs to be activated or deactivated)

  If your game starts with a character following the PC,
  call StartFollowing *after* the player global is set.    \!

routine StartFollowing { return Activate(follow_daemon) }

routine StopFollowing { return Deactivate(follow_daemon) }

daemon follow_daemon { }

event in follow_daemon { ! if (verbroutine = &DoGo, &DoExit, &DoCrawl) and location ~= old_location ! ^ Future Boy! has a DoCrawl verb if (verbroutine = &DoGo, &DoExit, &DoEnter) and location ~= old_location MoveFollowers }

routine MoveFollowers { local i, mf

  if followers = 0
     return

  if location.disallow_follow
     return

  ! Don't allow following through or during a teleport sequence
  ! Roody's note: I don't really understand what the next two lines do, but
  ! I tried to change them to be less Hugo-shell-centric (since not everybody
  ! names their player object "you"    !	if player ~= you    !		return

#ifclear _ROODYLIB_H if player.type ~= character return #else if player.type ~= player_character return #endif

  for (i=0; i<followers; i++)
  {
     if follower_list[i] in old_location and
        follower_list[i] not in location and
        not follower_list[i].pause_following and
        not follower_list[i].disallow_follow
     {

        move follower_list[i] to location
        moved_follower[mf] = follower_list[i]

        mf++

     }
  }

  if (mf)
  {
     print ""
     FollowMessage(&MoveFollowers,1,mf) ! "So-and-so follows you."
  }    }

#if undefined PrintArrayList ! taken from misc.h … called from MoveFollowers:

! PrintArrayList(list, count) ! Prints count elements of the array list.

routine PrintArrayList(list, count) { local i for (i=1; i<=count; i++) { if i > 1: “ “; The(array list[i-1]) if i < count and count > 2: “,”; if i = count-1: print “ “; AND_WORD; } return false } #endif ! if undefined PrintArrayList

routine FollowMessage(r, num, a, b) { if NewFollowMessages(r, num, a, b): return

  select r
  case &MoveFollowers
  {
     select num
        case 1:
        {
           print capital PrintArrayList(moved_follower, a);
           " follow";
           if a = 1 and moved_follower[0] is not plural:  "s";
           if not location.follow_message
           {
              print " ";
              if player_person = 1,2
              {
                 print player.pronoun #2;
              }
              else
                 print player.name;
              "."
           }
           event_flag = true
        }
  }    }

routine NewFollowMessages(r, num, a, b) { return false } #endif ! #ifset _FOLLOW_H

Examples

! this code assumes you have already run "StartFollowing"
! (must be done AFTER the player global is set in init routine)
character friendlygiant "friendly giant"
{
   article "the"
   adjective "friendly"
   noun "giant"
   order_response
      {
      ! a response to GIANT, FOLLOW ME
      if verbroutine = &DoFollow and object = player  ! DoFollow can be found in verbstub
          {
          if self is following
              "The giant says, \"I'm already following you!\""
          else
              {
              "The giant says, \"OK!\""
              AddFollower(self)
              }
          return true
          }
      elseif verbroutine = &DoStop ! DoStop is made up for this example
          {
          if self is not following
              "The giant says, \"I wasn't following you!\""
          else
              {
              "The giant says, \"OK!\""
              RemoveFollower(self)
              }
          return true
          }
      return false ! for other commands, do the normal behavior
      }
}

room tinyroom "Cramped Space"
{
   long_desc
       "Man, this place is tiny."
   out_to giant_hall
   disallow_follow 1 ! (true so our giant can't follow us in here)
}

! here is an example of a character that will only follow under
! certain circumstances
character rats "rats"
{
   article "the"
   noun "rats"
   disallow_follow
      {
      if not Contains(player,musicpipe) ! is the player not holding the pipe instrument?
         return true
      else
         return false
      }
   is plural
}