dw_fluffos_v1/
dw_fluffos_v1/fluffos-1.22c11/
dw_fluffos_v1/fluffos-1.22c11/ChangeLog.old/
dw_fluffos_v1/fluffos-1.22c11/Win32/
dw_fluffos_v1/fluffos-1.22c11/compat/
dw_fluffos_v1/fluffos-1.22c11/compat/simuls/
dw_fluffos_v1/fluffos-1.22c11/include/
dw_fluffos_v1/fluffos-1.22c11/mudlib/
dw_fluffos_v1/fluffos-1.22c11/testsuite/
dw_fluffos_v1/fluffos-1.22c11/testsuite/clone/
dw_fluffos_v1/fluffos-1.22c11/testsuite/command/
dw_fluffos_v1/fluffos-1.22c11/testsuite/data/
dw_fluffos_v1/fluffos-1.22c11/testsuite/etc/
dw_fluffos_v1/fluffos-1.22c11/testsuite/include/
dw_fluffos_v1/fluffos-1.22c11/testsuite/inherit/
dw_fluffos_v1/fluffos-1.22c11/testsuite/inherit/master/
dw_fluffos_v1/fluffos-1.22c11/testsuite/log/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/compiler/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/efuns/
dw_fluffos_v1/fluffos-1.22c11/testsuite/single/tests/operators/
dw_fluffos_v1/fluffos-1.22c11/testsuite/u/
dw_fluffos_v1/fluffos-1.22c11/tmp/
dw_fluffos_v1/lib/
dw_fluffos_v1/lib/binaries/cmds/
dw_fluffos_v1/lib/binaries/cmds/creator/
dw_fluffos_v1/lib/binaries/cmds/living/
dw_fluffos_v1/lib/binaries/cmds/player/
dw_fluffos_v1/lib/binaries/d/admin/obj/
dw_fluffos_v1/lib/binaries/d/liaison/
dw_fluffos_v1/lib/binaries/global/virtual/
dw_fluffos_v1/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v1/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v1/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v1/lib/binaries/obj/misc/
dw_fluffos_v1/lib/binaries/obj/misc/buckets/
dw_fluffos_v1/lib/binaries/obj/monster/
dw_fluffos_v1/lib/binaries/obj/reactions/
dw_fluffos_v1/lib/binaries/obj/reagents/
dw_fluffos_v1/lib/binaries/secure/cmds/creator/
dw_fluffos_v1/lib/binaries/secure/master/
dw_fluffos_v1/lib/binaries/std/
dw_fluffos_v1/lib/binaries/std/dom/
dw_fluffos_v1/lib/binaries/std/effects/object/
dw_fluffos_v1/lib/binaries/std/guilds/
dw_fluffos_v1/lib/binaries/std/languages/
dw_fluffos_v1/lib/binaries/std/races/
dw_fluffos_v1/lib/binaries/std/room/
dw_fluffos_v1/lib/binaries/std/room/basic/
dw_fluffos_v1/lib/binaries/std/shops/
dw_fluffos_v1/lib/binaries/std/shops/inherit/
dw_fluffos_v1/lib/binaries/www/
dw_fluffos_v1/lib/cmds/guild-race/
dw_fluffos_v1/lib/cmds/guild-race/crafts/
dw_fluffos_v1/lib/cmds/guild-race/other/
dw_fluffos_v1/lib/cmds/playtester/
dw_fluffos_v1/lib/cmds/playtester/senior/
dw_fluffos_v1/lib/d/admin/
dw_fluffos_v1/lib/d/admin/log/
dw_fluffos_v1/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v1/lib/d/admin/meetings/
dw_fluffos_v1/lib/d/admin/obj/
dw_fluffos_v1/lib/d/admin/room/we_care/
dw_fluffos_v1/lib/d/admin/save/
dw_fluffos_v1/lib/d/dist/
dw_fluffos_v1/lib/d/dist/mtf/
dw_fluffos_v1/lib/d/dist/pumpkin/
dw_fluffos_v1/lib/d/dist/pumpkin/chars/
dw_fluffos_v1/lib/d/dist/pumpkin/desert/
dw_fluffos_v1/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v1/lib/d/dist/pumpkin/hospital/
dw_fluffos_v1/lib/d/dist/pumpkin/inherit/
dw_fluffos_v1/lib/d/dist/pumpkin/map/
dw_fluffos_v1/lib/d/dist/pumpkin/plain/
dw_fluffos_v1/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v1/lib/d/dist/pumpkin/save/
dw_fluffos_v1/lib/d/dist/pumpkin/squash/
dw_fluffos_v1/lib/d/dist/pumpkin/terrain/
dw_fluffos_v1/lib/d/dist/pumpkin/woods/
dw_fluffos_v1/lib/d/dist/start/
dw_fluffos_v1/lib/d/learning/TinyTown/buildings/
dw_fluffos_v1/lib/d/learning/TinyTown/map/
dw_fluffos_v1/lib/d/learning/TinyTown/roads/
dw_fluffos_v1/lib/d/learning/add_command/
dw_fluffos_v1/lib/d/learning/arms_and_weps/
dw_fluffos_v1/lib/d/learning/chars/
dw_fluffos_v1/lib/d/learning/cutnpaste/
dw_fluffos_v1/lib/d/learning/examples/npcs/
dw_fluffos_v1/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v1/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v1/lib/d/learning/functions/
dw_fluffos_v1/lib/d/learning/handlers/
dw_fluffos_v1/lib/d/learning/help_topics/npcs/
dw_fluffos_v1/lib/d/learning/help_topics/objects/
dw_fluffos_v1/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v1/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v1/lib/d/learning/items/
dw_fluffos_v1/lib/d/learning/save/
dw_fluffos_v1/lib/d/liaison/
dw_fluffos_v1/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v1/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v1/lib/db/
dw_fluffos_v1/lib/doc/
dw_fluffos_v1/lib/doc/creator/
dw_fluffos_v1/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v1/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v1/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v1/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v1/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v1/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v1/lib/doc/creator/autodoc/std/key/
dw_fluffos_v1/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v1/lib/doc/creator/autodoc/std/map/
dw_fluffos_v1/lib/doc/creator/autodoc/std/race/
dw_fluffos_v1/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v1/lib/doc/creator/files/
dw_fluffos_v1/lib/doc/creator/policy/
dw_fluffos_v1/lib/doc/creator/room/
dw_fluffos_v1/lib/doc/effects/
dw_fluffos_v1/lib/doc/ideas/
dw_fluffos_v1/lib/doc/known_command/
dw_fluffos_v1/lib/doc/lpc/basic_manual/
dw_fluffos_v1/lib/doc/lpc/intermediate/
dw_fluffos_v1/lib/doc/new/add_command/
dw_fluffos_v1/lib/doc/new/handlers/
dw_fluffos_v1/lib/doc/new/living/
dw_fluffos_v1/lib/doc/new/living/race/
dw_fluffos_v1/lib/doc/new/living/spells/
dw_fluffos_v1/lib/doc/new/player/
dw_fluffos_v1/lib/doc/new/room/guild/
dw_fluffos_v1/lib/doc/new/room/outside/
dw_fluffos_v1/lib/doc/new/room/storeroom/
dw_fluffos_v1/lib/doc/object/
dw_fluffos_v1/lib/doc/playtesters/
dw_fluffos_v1/lib/doc/policy/
dw_fluffos_v1/lib/doc/weapons/
dw_fluffos_v1/lib/global/handlers/
dw_fluffos_v1/lib/global/virtual/setup_compiler/
dw_fluffos_v1/lib/include/
dw_fluffos_v1/lib/include/cmds/
dw_fluffos_v1/lib/include/effects/
dw_fluffos_v1/lib/include/npc/
dw_fluffos_v1/lib/include/shops/
dw_fluffos_v1/lib/net/daemon/chars/
dw_fluffos_v1/lib/net/inherit/
dw_fluffos_v1/lib/net/intermud3/
dw_fluffos_v1/lib/net/intermud3/services/
dw_fluffos_v1/lib/net/obj/
dw_fluffos_v1/lib/net/save/
dw_fluffos_v1/lib/net/smnmp/
dw_fluffos_v1/lib/net/snmp/
dw_fluffos_v1/lib/obj/amulets/
dw_fluffos_v1/lib/obj/b_day/
dw_fluffos_v1/lib/obj/examples/
dw_fluffos_v1/lib/obj/food/alcohol/
dw_fluffos_v1/lib/obj/food/chocolates/
dw_fluffos_v1/lib/obj/food/fruits/
dw_fluffos_v1/lib/obj/food/meat/
dw_fluffos_v1/lib/obj/food/nuts/
dw_fluffos_v1/lib/obj/food/seafood/
dw_fluffos_v1/lib/obj/food/vegetables/
dw_fluffos_v1/lib/obj/fungi/
dw_fluffos_v1/lib/obj/furnitures/artwork/
dw_fluffos_v1/lib/obj/furnitures/bathroom/
dw_fluffos_v1/lib/obj/furnitures/beds/
dw_fluffos_v1/lib/obj/furnitures/cabinets/
dw_fluffos_v1/lib/obj/furnitures/chairs/
dw_fluffos_v1/lib/obj/furnitures/chests/
dw_fluffos_v1/lib/obj/furnitures/clocks/
dw_fluffos_v1/lib/obj/furnitures/crockery/
dw_fluffos_v1/lib/obj/furnitures/cupboards/
dw_fluffos_v1/lib/obj/furnitures/cushions/
dw_fluffos_v1/lib/obj/furnitures/fake_plants/
dw_fluffos_v1/lib/obj/furnitures/lamps/
dw_fluffos_v1/lib/obj/furnitures/mirrors/
dw_fluffos_v1/lib/obj/furnitures/outdoor/
dw_fluffos_v1/lib/obj/furnitures/safes/
dw_fluffos_v1/lib/obj/furnitures/shelves/
dw_fluffos_v1/lib/obj/furnitures/sideboards/
dw_fluffos_v1/lib/obj/furnitures/sofas/
dw_fluffos_v1/lib/obj/furnitures/stoves/
dw_fluffos_v1/lib/obj/furnitures/tables/
dw_fluffos_v1/lib/obj/furnitures/wardrobes/
dw_fluffos_v1/lib/obj/handlers/
dw_fluffos_v1/lib/obj/handlers/autodoc/
dw_fluffos_v1/lib/obj/jewellery/anklets/
dw_fluffos_v1/lib/obj/jewellery/bracelets/
dw_fluffos_v1/lib/obj/jewellery/earrings/
dw_fluffos_v1/lib/obj/jewellery/misc/
dw_fluffos_v1/lib/obj/jewellery/necklaces/
dw_fluffos_v1/lib/obj/jewellery/rings/
dw_fluffos_v1/lib/obj/media/
dw_fluffos_v1/lib/obj/misc/buckets/
dw_fluffos_v1/lib/obj/misc/jars/
dw_fluffos_v1/lib/obj/misc/papers/
dw_fluffos_v1/lib/obj/misc/player_shop/
dw_fluffos_v1/lib/obj/misc/shops/
dw_fluffos_v1/lib/obj/misc/traps/
dw_fluffos_v1/lib/obj/monster/
dw_fluffos_v1/lib/obj/monster/godmother/
dw_fluffos_v1/lib/obj/monster/transport/
dw_fluffos_v1/lib/obj/plants/inherit/
dw_fluffos_v1/lib/obj/potions/
dw_fluffos_v1/lib/open/boards/
dw_fluffos_v1/lib/save/autodoc/
dw_fluffos_v1/lib/save/bank_accounts/
dw_fluffos_v1/lib/save/boards/frog/
dw_fluffos_v1/lib/save/books/bed_catalog/
dw_fluffos_v1/lib/save/creators/
dw_fluffos_v1/lib/save/mail/
dw_fluffos_v1/lib/save/mail/p/
dw_fluffos_v1/lib/save/newsrc/b/
dw_fluffos_v1/lib/save/newsrc/c/
dw_fluffos_v1/lib/save/newsrc/d/
dw_fluffos_v1/lib/save/newsrc/f/
dw_fluffos_v1/lib/save/newsrc/p/
dw_fluffos_v1/lib/save/newsrc/s/
dw_fluffos_v1/lib/save/newsrc/w/
dw_fluffos_v1/lib/save/players/c/
dw_fluffos_v1/lib/save/players/d/
dw_fluffos_v1/lib/save/players/g/
dw_fluffos_v1/lib/save/players/p/
dw_fluffos_v1/lib/save/players/s/
dw_fluffos_v1/lib/save/soul/data/
dw_fluffos_v1/lib/save/tasks/
dw_fluffos_v1/lib/save/vaults/
dw_fluffos_v1/lib/secure/cmds/lord/
dw_fluffos_v1/lib/secure/config/
dw_fluffos_v1/lib/secure/items/
dw_fluffos_v1/lib/secure/player/
dw_fluffos_v1/lib/soul/
dw_fluffos_v1/lib/soul/i/
dw_fluffos_v1/lib/soul/j/
dw_fluffos_v1/lib/soul/k/
dw_fluffos_v1/lib/soul/o/
dw_fluffos_v1/lib/soul/q/
dw_fluffos_v1/lib/soul/to_approve/
dw_fluffos_v1/lib/soul/u/
dw_fluffos_v1/lib/soul/v/
dw_fluffos_v1/lib/soul/wish_list/
dw_fluffos_v1/lib/soul/y/
dw_fluffos_v1/lib/soul/z/
dw_fluffos_v1/lib/std/creator/
dw_fluffos_v1/lib/std/effects/
dw_fluffos_v1/lib/std/effects/attached/
dw_fluffos_v1/lib/std/effects/external/
dw_fluffos_v1/lib/std/effects/fighting/
dw_fluffos_v1/lib/std/effects/other/
dw_fluffos_v1/lib/std/environ/
dw_fluffos_v1/lib/std/guilds/
dw_fluffos_v1/lib/std/hospital/
dw_fluffos_v1/lib/std/house/
dw_fluffos_v1/lib/std/house/onebedhouse/
dw_fluffos_v1/lib/std/house/onebedhut/
dw_fluffos_v1/lib/std/house/tworoomflat/
dw_fluffos_v1/lib/std/languages/
dw_fluffos_v1/lib/std/liquids/
dw_fluffos_v1/lib/std/nationality/
dw_fluffos_v1/lib/std/nationality/accents/
dw_fluffos_v1/lib/std/nationality/accents/national/
dw_fluffos_v1/lib/std/nationality/accents/regional/
dw_fluffos_v1/lib/std/npc/goals/
dw_fluffos_v1/lib/std/npc/goals/basic/
dw_fluffos_v1/lib/std/npc/goals/misc/
dw_fluffos_v1/lib/std/npc/inherit/
dw_fluffos_v1/lib/std/npc/plans/
dw_fluffos_v1/lib/std/npc/plans/basic/
dw_fluffos_v1/lib/std/outsides/
dw_fluffos_v1/lib/std/races/shadows/
dw_fluffos_v1/lib/std/room/basic/topography/
dw_fluffos_v1/lib/std/room/controller/
dw_fluffos_v1/lib/std/room/controller/topography/
dw_fluffos_v1/lib/std/room/furniture/games/
dw_fluffos_v1/lib/std/room/furniture/inherit/
dw_fluffos_v1/lib/std/room/inherit/carriage/
dw_fluffos_v1/lib/std/room/inherit/topography/
dw_fluffos_v1/lib/std/room/punishments/
dw_fluffos_v1/lib/std/room/topography/area/
dw_fluffos_v1/lib/std/room/topography/iroom/
dw_fluffos_v1/lib/std/room/topography/milestone/
dw_fluffos_v1/lib/std/shadows/
dw_fluffos_v1/lib/std/shadows/attached/
dw_fluffos_v1/lib/std/shadows/curses/
dw_fluffos_v1/lib/std/shadows/disease/
dw_fluffos_v1/lib/std/shadows/fighting/
dw_fluffos_v1/lib/std/shadows/room/
dw_fluffos_v1/lib/std/shops/controllers/
dw_fluffos_v1/lib/std/shops/objs/
dw_fluffos_v1/lib/std/shops/player_shop/
dw_fluffos_v1/lib/std/shops/player_shop/office_code/
dw_fluffos_v1/lib/std/socket/
dw_fluffos_v1/lib/www/
dw_fluffos_v1/lib/www/external/autodoc/
dw_fluffos_v1/lib/www/external/java/telnet/Documentation/
dw_fluffos_v1/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v1/lib/www/external/java/telnet/examples/
dw_fluffos_v1/lib/www/external/java/telnet/tools/
dw_fluffos_v1/lib/www/pics/
dw_fluffos_v1/lib/www/secure/creator/
dw_fluffos_v1/lib/www/secure/editors/
dw_fluffos_v1/lib/www/secure/survey_results/
/*  -*- LPC -*-  */
/*
 * $Locker:  $
 * $Id: psoul.c,v 1.39 2003/06/09 20:29:52 pinkfish Exp $
 */
/**
 * This class controls the entire command queue for all player
 * objects.  Whenever a player tries to execute a command,
 * it gets placed in a queue here and eventually (during the
 * player's heart_beat()), the command will (hopefully) be executed.
 *
 * <p>Since this class is a nexus of control for player commands, it
 * is also the natural place for a number of other utilities and
 * functions which also affect the execution of all commands.
 * Among these are things like drunk_check(), do_soul(), etc.
 *
 * @see /global/new_parse->add_command()
 * @see /global/player->heart_beat()
 * @see query_passed_out_message()
 *
 * @author Pinkfish
 * @changed 3 November 1997 -- Sin
 *      Documented the bejeesus out of this thing.
 * @changed 4 Novemebr 1997 - Pinkfish
 *      Updated the documentation and changed the interupt system slightly.
 * @changed 22 Feburary 1998 - Pinkfish
 *      Fixed up the problems with the queueing system.
 */

#include <living.h>
#include <player.h>
#include <soul.h>
    
inherit "/global/alias";
inherit "/global/nickname";

nosave int time_left;    /* Time left for this round. */
nosave int tl_updated;   /* Last time the time_left was updated */
nosave int doing_it;
nosave int last_command;
nosave int bypass_queue;
nosave int flush_call_id; /* Id of teh call_out */
nosave string *queued_commands;
nosave string in_command;
nosave mixed interrupt;
nosave private function cmd = 0; 

#if !efun_defined(add_action)
protected mixed _process_input(string);
protected mixed command(string);
#endif


/**
 * @ignore
 */
void create() {
  time_left = ROUND_TIME;
  tl_updated = time();
  last_command = time();
  queued_commands = ({ });
} /* create() */

/**
 * To make the next single command be executed directly rather
 * than being placed in the command queue, call this function.
 */
void bypass_queue() { bypass_queue = 1; }

/**
 * Ensure that the player has no more time for executing commands.
 * This will force the next command to be queued.
 */
void no_time_left() {
  time_left = -ROUND_TIME;
} /* no_time_left() */

/**
 * This is a setup function that is called by the player object.
 * It is used to register the lower_check() and drunk_check()
 * functions.  Plus it initializes the alias object, the
 * nickname object, and the history object.
 */

protected int drunk_check(string str);

void soul_commands() {
#if efun_defined(add_action)
  add_action("lower_check","*", -10000);
  add_action((:drunk_check:),"*", 10000);
#endif
  alias_commands();
  nickname_commands();
  history_commands();
} /* soul_commands() */

/**
 * You can use this function to see if there are any commands
 * queued for this player.
 * @return the number of queued commands
 */
int query_queued_commands() {
  return sizeof(queued_commands);
} /* query_queued_commands() */

/**
 * Some of the soul commands force the target to do something.
 * An example is the 'tickle' soul, which forces the target to
 * 'giggle'.  Those soul-forces call this function.  But only
 * the soul object can use this function: any other object which calls
 * this function will be ignored.  This prevents this function
 * from being used to bypass the security checking on the
 * 'force' command.
 *
 * @param str the command being forced
 * @return 0 if the command was ignored, otherwise 1.
 */
int soul_com_force(string str) {
  if (file_name(previous_object()) != SOUL_OBJECT)
    return 0;
  command(str);
  return 1;
} /* soul_com_force() */

/**
 * All soul commands eventually call this function to output their
 * messages.  This is nothing more than a wrapper for say(), but
 * it provides a convenient name by which a shadow on the
 * player object can replace any soul behavior.
 *
 * @param str the string being printed
 * @prarm bing the avoid array
 */
void do_soul(string str, mixed bing) {
  say(str, bing);
} /* do_soul() */

/**
 * The amount of time units left.  A time unit is 1/40th of a second.
 */
int query_time_left() {
  time_left += ((time() - tl_updated) / 2) * ROUND_TIME;
  if(time_left > ROUND_TIME)
    time_left = ROUND_TIME;
  tl_updated = time();
  
  return time_left;
} /* query_time_left() */

/**
 * Change the amount of time a player has left.  You call this after a command
 * has been executed to make it take more time.
 * @param i the amount of time units to change by
 * @return the amount of time left
 */
int adjust_time_left(int i) {
   return time_left += i;
} /* adjust_time_left() */

private void do_flush(int first) {
  int i;
  string str;

  if ( ( time_left < 0 ) || !sizeof( queued_commands ) ||
       ( this_object()->queue_commands(queued_commands[0]) &&
         !this_object()->query_creator() ) ) {
    return;
  }

  if (!first) {
    str = queued_commands[0];
    queued_commands = queued_commands[1..];
    doing_it = 1;
    catch(command(str));
    doing_it = 0;
    if (!sizeof(queued_commands)) {
      /* The end! */
      queued_commands = ({ });
      doing_alias = ([ ]);
    }
    return ;
  }
  for (i = 0; (i < 2) && (i < sizeof(queued_commands)); i++) {
    flush_call_id = call_out((: do_flush(0) :), 1);
  }
  flush_call_id = call_out((: do_flush(1) :), 2);
} /* do_flush() */

private void call_interrupt(int time_left, object interupter) {
   mixed stuff;

   stuff = interrupt;
   interrupt = 0;
   /* The previous object is the person interupting us. */
   if (pointerp(stuff)) {
      catch(call_other(stuff[1],
                       stuff[0],
                       time_left,
                       stuff[2],
                       this_object(),
                       interupter,
                       in_command));
   } else if (functionp(stuff)) {
      catch(evaluate(stuff,
                     time_left,
                     this_object(),
                     interupter,
                     in_command));
   }
} /* call_interrupt() */

/**
 * This method flushes all the queued commands.  It increments the time by the
 * ROUND_TIME define and checks to see if any of the commands now need to be
 * executed.  This should be called each heart beat..
 *
 * @see /global/player->heart_beat()
 */
protected void flush_queue() {
  query_time_left();
  remove_call_out(flush_call_id);
  do_flush(1);
  if (!sizeof(queued_commands)) {
    /* Ok... check to see if an interupt was set up */
    if (interrupt && time_left > 0) {
      call_interrupt(0, this_object());
    }
    in_alias_command = 0;
    doing_alias = ([ ]);
    if (!sizeof(queued_commands)) {
      return ;
    }
    doing_alias = ([ ]);
    in_alias_command = 0;
  }
} /* flush_queue() */

/**
 * Sets the function to be executed if the command is interrupted.
 * It is also executed if teh command finished.  If it is interrupted
 * the first arguement to the called function will be the amount of time
 * it had left to complete.  If it complets successfuly, this
 * argument will be 0.  If the first argument is a function pointer,
 * this will be used instead.<p>
 *
 * Eg: set_interupt_command("frog", this_object());<p>
 * void frog(int time_left, mixed arg) { <p>
 * ... <p>
 * }
 *
 * @param func the function to call back
 * @param ob the object to call the function on
 * @param arg the argument to pass to the function
 * @example
 * ...
 * void frog(int time_left, mixed arg);
 * ...
 * set_interupt_commant((: frog :));
 * ...
 * void frog(int time_left, mixed arg) {
 *    ...
 * } /\* frog() *\/
 */
void set_interupt_command(mixed func, mixed ob, mixed arg) {
  if (!functionp(func)) {
    interrupt = ({ func, ob, arg });
    if ( !stringp( func ) )
      interrupt = 0;
  } else {
    interrupt = func;
  }
} /* set_interupt_command() */

/**
 * This method returns the current value associated with tine interupt
 * command.
 * @return the current interupt command data
 */
mixed *query_interupt_command() {
   return interrupt;
} /* query_interupt_command_func() */

/**
 * Fixes a spelling error.   This one only takes a function pointer as an
 * input.
 *
 * @param func the function pointer to call back with
 */
void set_interrupt_command(function func) {
  set_interupt_command(func, 0, 0);
} /* set_interrupt_command() */

/**
 * This is called by the stop command.  It sets the entire queue back to
 * empty.  It calls the interrupt functions and stuff if they need to be
 * called.
 */
void remove_queue() {
   queued_commands = ({ });
   if ( interrupt && ( time_left < 0 ) ) {
      call_interrupt(-time_left, this_object());
   }
   tell_object( this_object(), "Removed queue.\n" );
   if (this_object()->query_lord()) {
     /* Just in case something really bad happens...  Let lords fix it */
     time_left = 0;
   } else {
     /* Make sure they cannot do anything for a heartbeat */
     time_left = -DEFAULT_TIME;
   }
} /* remove_queue() */

/**
 * This method interupts the current command.
 * @param interupter the person interupting the command
 */
void interupt_command(object interupter) {
   if (interupter) {
      call_interrupt(-time_left, interupter);
   }
} /* interupt_command() */

/** 
 * Use this function to set a function that is called with the players input
 * before the command handlers get to it, return 1 from the function if the
 * input needs no further parsing (ie the command is handled)
 *
 * @param func = function in the players environment to call.
 */

void command_override(function func){
  if(!functionp(func))
    error("command_override needs a function!");
  cmd = func;
}

/**
 * This poorly named function was originally used to affect the
 * player's behavior when they are drunk, and to prevent any
 * player from doing anything in the event that they are passed
 * out.  Now the function also is responsible for adding commands
 * to the player's command queue, for implementing the 'stop'
 * and 'restart' commands, and for ensuring that the player can quit
 * the game, even when queueing.
 *
 * <p>To see if a player is passed out, it checks the
 * "passed out" property.  If that property is nonzero, then
 * the player will be prevented from doing the command unless
 * that player is also a creator.  By default, it will print
 * a message that says: "You are unconscious.  You can't do
 * anything.\n".  If the function query_passed_out_message() is
 * defined on the player object (usually by a shadow), and
 * returns a string, then that string is printed instead.
 *
 * <p>This function is registered with
 * add_action("drunk_check", "*", 10000),
 * so it can be avoided by registering a higher priority add_action.
 * But that is not necessary, because if bypass_queue() has
 * been called, this function will do nothing.  Please note that
 * you should not be using add_action.
 *
 * @return 0 if nothing was done, 1 if drunk_check() blocked
 * the command.
 * @param str the command being executed
 *
 * @see /global/new_parse->add_command()
 */
protected int drunk_check(string str) {
   string *rabbit;
   string *green;
   string mess;
   string comm;
   string arg;

   if(cmd){
     object owner = function_owner(cmd);
     if(owner && owner == environment(this_player())){
       int res = evaluate(cmd, str);
       if(res)
         return res;
     } else cmd = 0;
   }

   if ( in_command == str ) {
      in_command = 0;
      sscanf(str, "%s %*s", str);
      if (is_doing_alias(str)) {
         this_object()->add_failed_mess(this_object(),
             "Recursive aliases. Bad "+
             ({"thing","boy","girl"})[(int)this_object()->query_gender()]+
                ".\n", ({ }));
      }
      return 0;
   }
   if ( bypass_queue ) {
      bypass_queue = 0;
      return 0;
   }
   last_command = time();
   if ( this_object()->query_property( PASSED_OUT ) ||
         !interactive( this_object() ) ) {
      if ( ( str == "quit" ) || ( str == "quit_old" ) ) {
         return 0;
      }
      mess = this_object()->query_passed_out_message();
      if ( !stringp( mess ) ) {
         mess = "You are unconscious.  You can't do anything.\n";
      }
      write( mess );
      if ( !this_object()->query_creator() ) {
         return 1;
      }
      write( "On the other hand, you're a creator...\n" );
   }
   if ( ( str == "stop" ) || ( str == "restart" ) ) {
      remove_queue();
      return 0;
   }
   if ( stringp( str ) ) {
      if ( str[ 0 .. 4 ] == "stop " ) {
         return 0;
      }
   }

   /*
    * If: there's no time left
    * or: commands are to be queued (e.g. spell casting) and this is a player
    * or: if we have queueing commands and we are not currently executing
    *     a command off the stack
    * or: we are trying to do a flush
    * then queue the command.
    */
   if ( ( time_left < 0 ) ||
        // Spell casting check
        (this_object()->queue_commands(str) &&
         !this_object()->query_creator()) ||
         ( !doing_it && ( sizeof( queued_commands ) ||
         ( find_call_out( flush_call_id ) != -1 ) ) ) ) {
      /* Only print commands which are not in upper case... */
      rabbit = explode(str, " ");
      if (rabbit[0] != upper_case(rabbit[0])) {
         write( "Queued command: "+ str +"\n" );
      }
      if ( str == "quit" ) {
         write( "If you are trying to quit and it is queueing things, use "
               "\"stop\" to stop your commands, and or \"restart\" to start "
               "your heartbeat.\n" );
      }
      /*
       * The command should always go on the end because the aliases
       * in the queue are expanded elsewhere...
       */
      if(sizeof(queued_commands) < 256) {
        // Queuing the same command repeatedly costs more time.
        // it checks for there being more than one word in the command to
        // avoid making movement aliases very slow.
        if(sizeof(rabbit) > 1 && member_array(str, queued_commands) != -1)
          time_left -= (DEFAULT_TIME / 2);
        queued_commands += ({ str });
      }
      return 1;
   }

   if (interrupt) {
      call_interrupt(0, this_object());
   }
   interrupt = 0;
   in_command = str;

   /* Get the args and stuff to run the alias. */
   if (sscanf(str, "%s %s", comm, arg) != 2) {
      comm = str;
      arg = "";
   }
   rabbit = run_alias(comm, arg);
   if (rabbit) {
      /* Set us as running the alias. */
      set_doing_alias(comm);
      green = queued_commands;
      queued_commands = ({ });
      foreach (comm in rabbit) {
         catch(command(comm));
      }
      queued_commands += green;
#if USE_ADD_ACTION
   } else if(sizeof(str) > 512) {
     write("Command too long.\n");
#endif
   } else {
      time_left -= DEFAULT_TIME;
      command(str);
   }

   if (interrupt && time_left >= 0) {
      call_interrupt(0, this_object());
   }
   return 1;
} /* drunk_check() */

/**
 * This is the command called by the driver on a player object every
 * time a command is executed.  It expands the history comands.
 *
 * @param str the string to expand
 * @return the expanded history string
 */
protected string process_input(string str) {
  float secs;
  int t = time_expression{
    reset_eval_cost();
    if (str[0] == '.')
      str = expand_history(str[1..]);
    else if (str[0] == '^')
      str = substitute_history(str[1..]);
    this_object()->add_history(str);
#if efun_defined(add_action)
    return str;
#else
    _process_input(str);
  };
  
  secs = t/1000000.0;

  if((secs > 1.0) &&
     (strlen(str) < 2 || str[0..1] != "su") &&
     str != "upgrade") {
    log_file("GARBAGE", "%s command: %s time: %:3f place: %s\n",  
       ctime(time())[4..18], str, secs, 
       file_name(environment()));
    if(this_object()->query_creator())
      printf("\nThat command froze the mud for %:3f "
       "seconds.\n\n", secs);
  } 
  return 0;
#endif  
} /* process_input() */

#if !efun_defined(add_action)
/** @ignore yes */
protected mixed _process_input(string str){
  object ob;
  int i;
  string* bits;
  
  if(str == "") {
    return 0;
  }
  
  ob = this_player();
  efun::set_this_player(this_object());
  
  _notify_fail(0);

  /* Strip leading spaces */
  while (str[0] == ' ') {
    str = str[1..];
  }

  if (str == ""){
      efun::set_this_player(ob);
      return 0;
    }

  /* Strip trailing spaces */
  while(str[<1] == ' ') {
    str = str[0..<2];
  }

  if (str == ""){
    efun::set_this_player(ob);
    return 0;
  }

  //strip %^%^
  //str = replace(str, "%^", "% ^");
  if (strsrch(str, "%^") != -1) {
    bits = explode("f" + str + "g", "%^");
    for (i = 1; i < sizeof(bits); i += 2) {
      if (bits[i][0..3] != "USER") {
         bits[i] = "USER_" + bits[i];
      }
    }
    bits[0] = bits[0][1..];
    bits[<1] = bits[<1][0..<2];
    str = implode(bits, "%^");
  }

  
  if(!drunk_check(str)) {
    if(!this_object()->exit_command(str)) {
      if(!this_object()->cmdAll(str)) {
        if(!this_object()->new_parser(str)) {
          if(!this_object()->lower_check(str)){
            if(!(str = query_notify_fail())){
              string *responses=({"What?", "Try something else."});
              receive(responses[random(sizeof(responses))]+"\n");
            } else {
              receive(str);
            }
            efun::set_this_player(ob);
            return 0;
          }
        }
      }
    }
  }
  efun::set_this_player(ob);
  return "bing";

} /* _process_input() */

/** @ignore yes */
protected mixed command(string cmd){
  int time = eval_cost();
  if(_process_input(cmd))
    return eval_cost() - time + 1; // on v22.2 eval_cost runs up, reverse for v22.1
  return 0;
}
#endif

/**
 * This function will get called when all other commands and actions
 * have refused to do anything for this input from the user.  This
 * function adds some extra time for the user, and then returns.
 * 
 * <p>This function is registered via add_action() with a 
 * priority of -10000.  If you want to bypass it, then use a priority
 * higher than that.  If you want to see what strings get dropped by the
 * entire add_action() stack, then use a priority lower.
 *
 * @parms str the user's input
 * @return 1 if the user's input is "stop", otherwise 0.
 */
int lower_check(string str) {
  query_time_left();
  return (str == "stop");
} /* lower_check() */