skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * This is the goal handler for the npcs.  It will handle all the goals
 * and ordering them, figuring out which goal to run.
 * @author Pinkfish
 * @started Thu Jul 30 17:06:19 PDT 1998
 */
#include <npc/goals.h>
// Local inherit stuff.
#include "goal_inherit.h"

class goal_information {
   mixed data;
   int priority;
   string *events;
}

class plan_info {
   int priority;
   mixed data;
}

// The index of the mapping is the goal.
private nosave mapping _goals;
private nosave mapping _events;
private nosave mapping _emotions;
// The format of this array is:
//  ({ priority, plan, priority, plan, ... })
private nosave mixed* _plans;
private nosave string  _current_plan;

private class goal_information query_goal_information(string goal);
void remove_goal_event(string goal, string event);
void add_goal_event(string goal, string event);
int query_goal_priority(string goal);
int check_current_plan_finished();

void create() {
   _goals = ([ ]);
   _events = ([ ]);
   _plans = ({ });
} /* create() */

/**
 * This method is *only* to be used for debugging.
 */
mapping query_goals() {
   return _goals;
} /* query_goals() */

/**
 * This method is *only* to be used for debugging.
 */
mapping query_events() {
   return _events;
} /* query_events() */

/**
 * This method will add a goal to the NPC.
 * @param goal the goal to add
 * @param data the data associated with the goal
 */
void add_goal(string goal, mixed data) {
   class goal_information frog;

   if (!goal->invarient(this_object())) {
      // Cannot add the goal.
      return ;
   }

   if (!_goals[goal]) {
      frog = new(class goal_information);
      frog->data = data;
      frog->priority = goal->query_priority(this_object(), data);
      frog->events = ({ });
      _goals[goal] = frog;
      goal->initialise(this_object(), goal, data);
   } else {
      goal->add_again(this_object(), query_goal_information(goal)->data, data);
   }
} /* add_goal() */

/**
 * This method removes the goal from the current goal list.
 * @param goal the goal to remove
 */
void remove_goal(string goal) {
   class goal_information frog;
   string event;

   frog = query_goal_information(goal);
   if (frog) {
      goal->finalise(this_object(), frog->data);
      foreach (event in frog->events) {
         remove_goal_event(goal, event);
      }
      map_delete(_goals, goal);
   }
} /* remove_goal() */

/**
 * This method gets the information associated with the goal.
 * @param goal the goal to get the information for
 * @return the goal information
 */
private class goal_information query_goal_information(string goal) {
   class goal_information frog;

   frog = _goals[goal];
   return frog;
} /* query_goal_information() */

/**
 * This method returns the data associated with this goal.
 * @param goal the goal to get the data for
 * @return the data associated with the goal
 * @see query_goal_priority()
 * @see set_goal_data()
 */
mixed query_goal_data(string goal) {
   class goal_information frog;

   frog = query_goal_information(goal);
   if (frog) {
      return frog->data;
   }
   return 0;
} /* query_goal_data() */

/**
 * This method returns the data associated with this goal.
 * @param goal the goal to get the data for
 * @param data the new data for the goal
 * @return 1 on success, 0 on failure
 * @see query_goal_priority()
 * @see query_goal_data()
 */
int set_goal_data(string goal, mixed data) {
   class goal_information frog;

   frog = query_goal_information(goal);
   if (frog) {
      frog->data = data;
      return 1;
   }
   return 0;
} /* set_goal_data() */

/**
 * This method returns the priotity of the goal.
 * @param goal the goal to query the priority of
 * @return the priority of the goal
 * @see change_goal_priority()
 */
int query_goal_priority(string goal) {
   class goal_information frog;

   frog = query_goal_information(goal);
   if (frog) {
      return frog->priority;
   }
   return GOAL_INVALID_PRIORITY;
} /* query_priority() */

/**
 * This method changes the priority of the specified goal.  It will recall
 * the query_priority() method on the goal to figure out the new priority.
 * @param goal the goal whose priority to change
 * @see add_goal_event()
 * @see remove_goal_event()
 * @see query_goal_priority()
 */
void change_goal_priority(string goal) {
   class goal_information frog;
   int new_priority;
   string evt;

   frog = query_goal_information(goal);
   if (frog) {
      new_priority = goal->query_priority(this_object(), frog->data);
      if (new_priority != frog->priority) {
         frog->priority = new_priority;
      }
      foreach (evt in frog->events) {
         /* Put itself back into the event list. */
         remove_goal_event(goal, evt);
         add_goal_event(goal, evt);
      }
   }
} /* change_goal_priority() */

/**
 * This method adds an event for a goal to react to.  This should only be
 * done from inside the goal initialisation code, and other parts of the
 * goal.  We will only add things for goals which we know about.
 * @param goal the goal the event is for
 * @param event the event name to react to
 * @see change_priority()
 * @see remove_goal_event()
 */
void add_goal_event(string goal, string event) {
   class goal_information frog;
   string test_goal;
   int i;
   int priority;
   int found;

   frog = query_goal_information(goal);
   if (frog) {
      if (!_events[event]) {
         _events[event] = ({ goal });
      } else if (member_array(goal, _events[event]) == -1) {
         // Place the goal into the list in priority order.
         priority = query_goal_priority(goal);
         while (i < sizeof(_events[event])) {
            test_goal = _events[event][i];
            if (query_goal_priority(_events[event][i]) < priority) {
               _events[event] = _events[event][0..i-1] + ({ goal }) +
                                _events[event][i..];
               found = 1;
               break;
            }
            i++;
         }
         if (!found) {
            _events[event] += ({ goal });
         }
      }
      frog->events += ({ event });
   }
} /* add_goal_event() */

/**
 * This method removes the goal event for the goal.
 * @param goal the goal to remove the event for
 * @param event the event name to not react to
 * @see add_goal_event()
 * @see change_priority()
 */
void remove_goal_event(string goal, string event) {
   class goal_information frog;

   frog = query_goal_information(goal);
   if (frog && _events[event]) {
      _events[event] -= ({ goal });
      if (!sizeof(_events[event])) {
         map_delete(_events, event);
      }
      frog->events -= ({ event });
   }
} /* remove_goal_event() */

/**
 * This method is called when an event needs to be notified about.
 * The event handling routines should try to be short.  They should
 * just modify the priority of something, or add a new goal to the
 * current list.
 * @param event the event to tell us about
 * @param information the information associated with the event
 */
varargs void notify_npc_event(string event, mixed *information ...) {
   string goal;

tell_creator("pinkfish", "%s %O\n", event, _events[event]);
   if (_events[event]) {
      foreach (goal in _events[event]) {
           // If the event is handled then we break out.
         if (goal->notify_of_event(this_object(),
                                   query_goal_information(goal)->data,
                                   event,
                                   information)) {
            return ;
         }
      }
   }

   if (sizeof(_plans)) {
      if (_plans[PLAN_PLAN]->notify_of_event(this_object(),
                                      ((class plan_info)_plans[PLAN_INFO])->data,
                                      event,
                                      information)) {
         check_current_plan_finished();
      }
   }
} /* notify_npc_event() */

/**
 * This activates the plan on the npc.
 * @param plan the plan to activate
 * @param goal the goal which is activating the plan
 */
void activate_plan(string plan,
                   string goal,
                   mixed data) {
   int priority;
   int pos;
   int i;
   int old;
   mixed *tmp;
   class plan_info info;

   priority = query_goal_priority(goal);
   /* First see if the plan is already activated. */
   pos = member_array(plan, _plans);
   if (pos != -1) {
      /* Update the data value */
      info = _plans[pos + PLAN_INFO];
      info->data = plan->combine_plans(info->data, data);
      if (info->priority != priority) {
         /* Priority has changed... Tricky... */
         /* First see if we should move up the list. */
         old = -1;
         for (i = pos - PLAN_ARRAY_SIZE; i >= 0; i -= PLAN_ARRAY_SIZE) {
            if (priority > ((class plan_info)_plans[i + PLAN_INFO])->priority) {
               old = i;
            } else {
               break;
            }
         }
         if (old != -1) {
            /* We move upwards! */
            tmp = _plans[pos..pos + PLAN_ARRAY_SIZE];
            _plans = _plans[0..pos - 1] + _plans[pos + PLAN_ARRAY_SIZE..];
            _plans = _plans[0..old - 1] + tmp + _plans[old..];
         } else {
            /* Check to see if we need to move down. */
            for (i = pos + PLAN_ARRAY_SIZE; i < sizeof(_plans);
                 i += PLAN_ARRAY_SIZE) {
               if (priority < ((class plan_info)_plans[i + PLAN_INFO])->priority) {
                  old = i;
               } else {
                  break;
               }
            }
            if (old != -1) {
               /* We move down... :( */
               tmp = _plans[old..old + PLAN_ARRAY_SIZE];
               _plans = _plans[0..old - 1] + _plans[old + PLAN_ARRAY_SIZE..];
               _plans = _plans[0..pos - 1] + tmp + _plans[pos..];
            }
         }
      }
   } else {
      old = -1;

      info = new(class plan_info);
      info->data = data;
      info->priority = priority;
      /* Try to find the right spot to put it into the array. */
      for (i = 0; i < sizeof(_plans); i += PLAN_ARRAY_SIZE) {
         if (priority > ((class plan_info)_plans[i + PLAN_INFO])->priority) {
            /* We go here... */
            _plans = _plans[0..i - 1] + ({ plan, info }) +
                     _plans[i..];
            old = i + PLAN_ARRAY_SIZE;
            break;
         }
      }
      if (i >= sizeof(_plans)) {
         _plans += ({ plan, info });
      }
   }

tell_creator("pinkfish", "Activating %O, %O, %O\n", _current_plan, _plans[PLAN_PLAN], _plans[PLAN_INFO]);
   /* Check to see if any plans should be suspended or activated. */
   if (_plans[PLAN_PLAN] != _current_plan) {
      if (_current_plan) {
         pos = member_array(_current_plan, _plans);
         if (pos != -1) {
            _plans[pos + PLAN_PLAN]->suspend_plan(this_object(),
                                                  ((class plan_info)_plans[pos + PLAN_INFO])->data);
         }
      }
      _plans[PLAN_PLAN]->activate_plan(this_object(),
                                       ((class plan_info)_plans[PLAN_INFO])->data);
      // Check to see if any of the plans are completed now...
      while (check_current_plan_finished());
   }
} /* activate_plan() */

/**
 * This method checks to see if the top plan is finished or not.
 * @param plan the plan to finish
 * @return 1 if the plan has been finished, 0 if not
 */
int check_current_plan_finished() {
   if (sizeof(_plans)) {
      if (_plans[PLAN_PLAN]->finished(this_object(),
                                      ((class plan_info)_plans[PLAN_INFO])->data)) {
         _plans = _plans[PLAN_ARRAY_SIZE..];
         if (sizeof(_plans)) {
            _plans[PLAN_PLAN]->activate_plan(this_object(),
                                             ((class plan_info)_plans[PLAN_INFO])->data);
         }
         return 1;
      }
   }
   return 0;
} /* finish_plan() */

/**
 * This method changes the data associated with the specified plan.  This
 * should only be called from the plan itself, as the plan will not be
 * informed of this change.
 * @param data the new data for the plan
 */
void set_plan_data(string plan, mixed data) {
   int pos;

   pos = member_array(plan, _plans);
   if (pos != -1) {
      ((class plan_info)_plans[pos + PLAN_INFO])->data = data;
   }
} /* set_plan_data() */

/** @ignore yes */
mixed *stats() {
   mixed *ret;
   string goal;
   class goal_information frog;
   int goal_num;
   int i;

   goal_num = 0;
   ret = ({ });
   foreach (goal in keys(_goals)) {
      frog = query_goal_information(goal);
      ret += ({ ({ "Goal " + goal_num + ") name", goal }) });
      ret += ({ ({ "Goal " + goal_num + ") events",
                   query_multiple_short(frog->events) }) });
      ret += ({ ({ "Goal " + goal_num + ") priority",  frog->priority }) });
      goal_num++;
   }

   for (i = 0; i < sizeof(_plans); i += PLAN_ARRAY_SIZE) {
      ret += ({ ({ "Plan " + goal_num + ") name", _plans[i + PLAN_PLAN] }) });
      ret += ({ ({ "Plan " + goal_num + ") priority",
                   ((class plan_info)_plans[i + PLAN_INFO])->priority }) });
   }

   return ret;
} /* stats() */

/**
 * This method sets the default data associated with the specified plan.
 * This should be things like global plan things, the level at which the
 * npc will run away.  Etc.
 * @param goal the goal to check the data for
 * @param plan the name of the plan
 * @param data the data associated with the plan
 * @see query_default_plan_data()
 */
void set_goal_plan_data(string goal, string plan, mixed data) {
   mixed goal_data;

   goal_data = query_goal_data(goal);
   goal->set_plan_data(this_object(), goal_data, plan, data);
} /* set_default_plan_data() */

/**
 * This method returns the data associated with the specified plan.
 * @param goal the foal to query the information for
 * @param plan the name of the plan to get the data for
 * @return the plans data
 * @see set_default_plan_data()
 */
mixed query_goal_plan_data(string goal, string plan) {
   mixed goal_data;

   goal_data = query_goal_data(goal);
   return goal->query_plan_data(this_object(), goal_data, plan);
} /* query_default_plan_data() */