dw_fluffos_v2/
dw_fluffos_v2/fluffos-2.9-ds2.05/
dw_fluffos_v2/fluffos-2.9-ds2.05/ChangeLog.old/
dw_fluffos_v2/fluffos-2.9-ds2.05/Win32/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/
dw_fluffos_v2/fluffos-2.9-ds2.05/compat/simuls/
dw_fluffos_v2/fluffos-2.9-ds2.05/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/clone/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/command/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/data/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/etc/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/include/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/inherit/master/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/log/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/compiler/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/efuns/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/single/tests/operators/
dw_fluffos_v2/fluffos-2.9-ds2.05/testsuite/u/
dw_fluffos_v2/fluffos-2.9-ds2.05/tmp/
dw_fluffos_v2/fluffos-2.9-ds2.05/windows/
dw_fluffos_v2/lib/
dw_fluffos_v2/lib/binaries/cmds/
dw_fluffos_v2/lib/binaries/cmds/creator/
dw_fluffos_v2/lib/binaries/cmds/living/
dw_fluffos_v2/lib/binaries/cmds/player/
dw_fluffos_v2/lib/binaries/d/admin/obj/
dw_fluffos_v2/lib/binaries/d/liaison/
dw_fluffos_v2/lib/binaries/global/virtual/
dw_fluffos_v2/lib/binaries/global/virtual/setup_compiler/
dw_fluffos_v2/lib/binaries/obj/handlers/autodoc/
dw_fluffos_v2/lib/binaries/obj/handlers/terrain_things/
dw_fluffos_v2/lib/binaries/obj/misc/
dw_fluffos_v2/lib/binaries/obj/misc/buckets/
dw_fluffos_v2/lib/binaries/obj/monster/
dw_fluffos_v2/lib/binaries/obj/reactions/
dw_fluffos_v2/lib/binaries/obj/reagents/
dw_fluffos_v2/lib/binaries/secure/cmds/creator/
dw_fluffos_v2/lib/binaries/secure/master/
dw_fluffos_v2/lib/binaries/std/
dw_fluffos_v2/lib/binaries/std/dom/
dw_fluffos_v2/lib/binaries/std/effects/object/
dw_fluffos_v2/lib/binaries/std/guilds/
dw_fluffos_v2/lib/binaries/std/languages/
dw_fluffos_v2/lib/binaries/std/races/
dw_fluffos_v2/lib/binaries/std/room/
dw_fluffos_v2/lib/binaries/std/room/basic/
dw_fluffos_v2/lib/binaries/std/shops/
dw_fluffos_v2/lib/binaries/std/shops/inherit/
dw_fluffos_v2/lib/binaries/www/
dw_fluffos_v2/lib/cmds/guild-race/
dw_fluffos_v2/lib/cmds/guild-race/crafts/
dw_fluffos_v2/lib/cmds/guild-race/other/
dw_fluffos_v2/lib/cmds/playtester/
dw_fluffos_v2/lib/cmds/playtester/senior/
dw_fluffos_v2/lib/d/admin/
dw_fluffos_v2/lib/d/admin/log/
dw_fluffos_v2/lib/d/admin/mapper/31-10-01/mapmaker/event/
dw_fluffos_v2/lib/d/admin/meetings/
dw_fluffos_v2/lib/d/admin/obj/
dw_fluffos_v2/lib/d/admin/room/we_care/
dw_fluffos_v2/lib/d/admin/save/
dw_fluffos_v2/lib/d/dist/
dw_fluffos_v2/lib/d/dist/mtf/
dw_fluffos_v2/lib/d/dist/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/chars/
dw_fluffos_v2/lib/d/dist/pumpkin/desert/
dw_fluffos_v2/lib/d/dist/pumpkin/gumboot/
dw_fluffos_v2/lib/d/dist/pumpkin/hospital/
dw_fluffos_v2/lib/d/dist/pumpkin/inherit/
dw_fluffos_v2/lib/d/dist/pumpkin/map/
dw_fluffos_v2/lib/d/dist/pumpkin/plain/
dw_fluffos_v2/lib/d/dist/pumpkin/pumpkin/
dw_fluffos_v2/lib/d/dist/pumpkin/save/
dw_fluffos_v2/lib/d/dist/pumpkin/squash/
dw_fluffos_v2/lib/d/dist/pumpkin/terrain/
dw_fluffos_v2/lib/d/dist/pumpkin/woods/
dw_fluffos_v2/lib/d/dist/start/
dw_fluffos_v2/lib/d/learning/TinyTown/buildings/
dw_fluffos_v2/lib/d/learning/TinyTown/map/
dw_fluffos_v2/lib/d/learning/TinyTown/roads/
dw_fluffos_v2/lib/d/learning/add_command/
dw_fluffos_v2/lib/d/learning/arms_and_weps/
dw_fluffos_v2/lib/d/learning/chars/
dw_fluffos_v2/lib/d/learning/cutnpaste/
dw_fluffos_v2/lib/d/learning/examples/npcs/
dw_fluffos_v2/lib/d/learning/examples/player_houses/npcs/
dw_fluffos_v2/lib/d/learning/examples/terrain_map/basic/
dw_fluffos_v2/lib/d/learning/functions/
dw_fluffos_v2/lib/d/learning/handlers/
dw_fluffos_v2/lib/d/learning/help_topics/npcs/
dw_fluffos_v2/lib/d/learning/help_topics/objects/
dw_fluffos_v2/lib/d/learning/help_topics/rcs_demo/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/crowd/
dw_fluffos_v2/lib/d/learning/help_topics/rooms/situations/
dw_fluffos_v2/lib/d/learning/items/
dw_fluffos_v2/lib/d/learning/save/
dw_fluffos_v2/lib/d/liaison/
dw_fluffos_v2/lib/d/liaison/NEWBIE/doc/
dw_fluffos_v2/lib/d/liaison/NEWBIE/save/oldlog/
dw_fluffos_v2/lib/db/
dw_fluffos_v2/lib/doc/
dw_fluffos_v2/lib/doc/creator/
dw_fluffos_v2/lib/doc/creator/autodoc/include/reaction/
dw_fluffos_v2/lib/doc/creator/autodoc/include/ritual_system/
dw_fluffos_v2/lib/doc/creator/autodoc/include/talker/
dw_fluffos_v2/lib/doc/creator/autodoc/include/terrain_map/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/baggage/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clock/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/clothing/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/cont_save/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/corpse/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/money/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/monster/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/scabbard/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/service_provider/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/state_changer/
dw_fluffos_v2/lib/doc/creator/autodoc/obj/wand/
dw_fluffos_v2/lib/doc/creator/autodoc/std/book_dir/
dw_fluffos_v2/lib/doc/creator/autodoc/std/key/
dw_fluffos_v2/lib/doc/creator/autodoc/std/learning/
dw_fluffos_v2/lib/doc/creator/autodoc/std/map/
dw_fluffos_v2/lib/doc/creator/autodoc/std/race/
dw_fluffos_v2/lib/doc/creator/autodoc/std/weapon_logic/
dw_fluffos_v2/lib/doc/creator/files/
dw_fluffos_v2/lib/doc/creator/policy/
dw_fluffos_v2/lib/doc/creator/room/
dw_fluffos_v2/lib/doc/effects/
dw_fluffos_v2/lib/doc/ideas/
dw_fluffos_v2/lib/doc/known_command/
dw_fluffos_v2/lib/doc/lpc/basic_manual/
dw_fluffos_v2/lib/doc/lpc/intermediate/
dw_fluffos_v2/lib/doc/new/add_command/
dw_fluffos_v2/lib/doc/new/handlers/
dw_fluffos_v2/lib/doc/new/living/
dw_fluffos_v2/lib/doc/new/living/race/
dw_fluffos_v2/lib/doc/new/living/spells/
dw_fluffos_v2/lib/doc/new/player/
dw_fluffos_v2/lib/doc/new/room/guild/
dw_fluffos_v2/lib/doc/new/room/outside/
dw_fluffos_v2/lib/doc/new/room/storeroom/
dw_fluffos_v2/lib/doc/object/
dw_fluffos_v2/lib/doc/playtesters/
dw_fluffos_v2/lib/doc/policy/
dw_fluffos_v2/lib/doc/weapons/
dw_fluffos_v2/lib/global/handlers/
dw_fluffos_v2/lib/global/virtual/setup_compiler/
dw_fluffos_v2/lib/include/
dw_fluffos_v2/lib/include/cmds/
dw_fluffos_v2/lib/include/effects/
dw_fluffos_v2/lib/include/npc/
dw_fluffos_v2/lib/include/shops/
dw_fluffos_v2/lib/net/daemon/chars/
dw_fluffos_v2/lib/net/inherit/
dw_fluffos_v2/lib/net/intermud3/
dw_fluffos_v2/lib/net/intermud3/services/
dw_fluffos_v2/lib/net/obj/
dw_fluffos_v2/lib/net/save/
dw_fluffos_v2/lib/net/smnmp/
dw_fluffos_v2/lib/net/snmp/
dw_fluffos_v2/lib/obj/amulets/
dw_fluffos_v2/lib/obj/b_day/
dw_fluffos_v2/lib/obj/examples/
dw_fluffos_v2/lib/obj/food/alcohol/
dw_fluffos_v2/lib/obj/food/chocolates/
dw_fluffos_v2/lib/obj/food/fruits/
dw_fluffos_v2/lib/obj/food/meat/
dw_fluffos_v2/lib/obj/food/nuts/
dw_fluffos_v2/lib/obj/food/seafood/
dw_fluffos_v2/lib/obj/food/vegetables/
dw_fluffos_v2/lib/obj/fungi/
dw_fluffos_v2/lib/obj/furnitures/artwork/
dw_fluffos_v2/lib/obj/furnitures/bathroom/
dw_fluffos_v2/lib/obj/furnitures/beds/
dw_fluffos_v2/lib/obj/furnitures/cabinets/
dw_fluffos_v2/lib/obj/furnitures/chairs/
dw_fluffos_v2/lib/obj/furnitures/chests/
dw_fluffos_v2/lib/obj/furnitures/clocks/
dw_fluffos_v2/lib/obj/furnitures/crockery/
dw_fluffos_v2/lib/obj/furnitures/cupboards/
dw_fluffos_v2/lib/obj/furnitures/cushions/
dw_fluffos_v2/lib/obj/furnitures/fake_plants/
dw_fluffos_v2/lib/obj/furnitures/lamps/
dw_fluffos_v2/lib/obj/furnitures/mirrors/
dw_fluffos_v2/lib/obj/furnitures/outdoor/
dw_fluffos_v2/lib/obj/furnitures/safes/
dw_fluffos_v2/lib/obj/furnitures/shelves/
dw_fluffos_v2/lib/obj/furnitures/sideboards/
dw_fluffos_v2/lib/obj/furnitures/sofas/
dw_fluffos_v2/lib/obj/furnitures/stoves/
dw_fluffos_v2/lib/obj/furnitures/tables/
dw_fluffos_v2/lib/obj/furnitures/wardrobes/
dw_fluffos_v2/lib/obj/handlers/
dw_fluffos_v2/lib/obj/handlers/autodoc/
dw_fluffos_v2/lib/obj/jewellery/anklets/
dw_fluffos_v2/lib/obj/jewellery/bracelets/
dw_fluffos_v2/lib/obj/jewellery/earrings/
dw_fluffos_v2/lib/obj/jewellery/misc/
dw_fluffos_v2/lib/obj/jewellery/necklaces/
dw_fluffos_v2/lib/obj/jewellery/rings/
dw_fluffos_v2/lib/obj/media/
dw_fluffos_v2/lib/obj/misc/buckets/
dw_fluffos_v2/lib/obj/misc/jars/
dw_fluffos_v2/lib/obj/misc/papers/
dw_fluffos_v2/lib/obj/misc/player_shop/
dw_fluffos_v2/lib/obj/misc/shops/
dw_fluffos_v2/lib/obj/misc/traps/
dw_fluffos_v2/lib/obj/monster/
dw_fluffos_v2/lib/obj/monster/godmother/
dw_fluffos_v2/lib/obj/monster/transport/
dw_fluffos_v2/lib/obj/plants/inherit/
dw_fluffos_v2/lib/obj/potions/
dw_fluffos_v2/lib/open/boards/
dw_fluffos_v2/lib/save/autodoc/
dw_fluffos_v2/lib/save/bank_accounts/
dw_fluffos_v2/lib/save/boards/frog/
dw_fluffos_v2/lib/save/books/bed_catalog/
dw_fluffos_v2/lib/save/creators/
dw_fluffos_v2/lib/save/mail/
dw_fluffos_v2/lib/save/mail/p/
dw_fluffos_v2/lib/save/soul/data/
dw_fluffos_v2/lib/save/tasks/
dw_fluffos_v2/lib/save/vaults/
dw_fluffos_v2/lib/secure/cmds/lord/
dw_fluffos_v2/lib/secure/config/
dw_fluffos_v2/lib/secure/items/
dw_fluffos_v2/lib/secure/player/
dw_fluffos_v2/lib/soul/
dw_fluffos_v2/lib/soul/i/
dw_fluffos_v2/lib/soul/j/
dw_fluffos_v2/lib/soul/k/
dw_fluffos_v2/lib/soul/o/
dw_fluffos_v2/lib/soul/q/
dw_fluffos_v2/lib/soul/to_approve/
dw_fluffos_v2/lib/soul/u/
dw_fluffos_v2/lib/soul/v/
dw_fluffos_v2/lib/soul/wish_list/
dw_fluffos_v2/lib/soul/y/
dw_fluffos_v2/lib/soul/z/
dw_fluffos_v2/lib/std/creator/
dw_fluffos_v2/lib/std/effects/
dw_fluffos_v2/lib/std/effects/attached/
dw_fluffos_v2/lib/std/effects/external/
dw_fluffos_v2/lib/std/effects/fighting/
dw_fluffos_v2/lib/std/effects/other/
dw_fluffos_v2/lib/std/environ/
dw_fluffos_v2/lib/std/guilds/
dw_fluffos_v2/lib/std/hospital/
dw_fluffos_v2/lib/std/house/
dw_fluffos_v2/lib/std/house/onebedhouse/
dw_fluffos_v2/lib/std/house/onebedhut/
dw_fluffos_v2/lib/std/house/tworoomflat/
dw_fluffos_v2/lib/std/languages/
dw_fluffos_v2/lib/std/liquids/
dw_fluffos_v2/lib/std/nationality/
dw_fluffos_v2/lib/std/nationality/accents/
dw_fluffos_v2/lib/std/nationality/accents/national/
dw_fluffos_v2/lib/std/nationality/accents/regional/
dw_fluffos_v2/lib/std/npc/goals/
dw_fluffos_v2/lib/std/npc/goals/basic/
dw_fluffos_v2/lib/std/npc/goals/misc/
dw_fluffos_v2/lib/std/npc/inherit/
dw_fluffos_v2/lib/std/npc/plans/
dw_fluffos_v2/lib/std/npc/plans/basic/
dw_fluffos_v2/lib/std/outsides/
dw_fluffos_v2/lib/std/races/shadows/
dw_fluffos_v2/lib/std/room/basic/topography/
dw_fluffos_v2/lib/std/room/controller/
dw_fluffos_v2/lib/std/room/controller/topography/
dw_fluffos_v2/lib/std/room/furniture/games/
dw_fluffos_v2/lib/std/room/furniture/inherit/
dw_fluffos_v2/lib/std/room/inherit/carriage/
dw_fluffos_v2/lib/std/room/inherit/topography/
dw_fluffos_v2/lib/std/room/punishments/
dw_fluffos_v2/lib/std/room/topography/area/
dw_fluffos_v2/lib/std/room/topography/iroom/
dw_fluffos_v2/lib/std/room/topography/milestone/
dw_fluffos_v2/lib/std/shadows/
dw_fluffos_v2/lib/std/shadows/attached/
dw_fluffos_v2/lib/std/shadows/curses/
dw_fluffos_v2/lib/std/shadows/disease/
dw_fluffos_v2/lib/std/shadows/fighting/
dw_fluffos_v2/lib/std/shadows/room/
dw_fluffos_v2/lib/std/shops/controllers/
dw_fluffos_v2/lib/std/shops/objs/
dw_fluffos_v2/lib/std/shops/player_shop/
dw_fluffos_v2/lib/std/shops/player_shop/office_code/
dw_fluffos_v2/lib/std/socket/
dw_fluffos_v2/lib/www/
dw_fluffos_v2/lib/www/external/autodoc/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/
dw_fluffos_v2/lib/www/external/java/telnet/Documentation/images/
dw_fluffos_v2/lib/www/external/java/telnet/examples/
dw_fluffos_v2/lib/www/external/java/telnet/tools/
dw_fluffos_v2/lib/www/pics/
dw_fluffos_v2/lib/www/secure/creator/
dw_fluffos_v2/lib/www/secure/editors/
dw_fluffos_v2/lib/www/secure/survey_results/
dw_fluffos_v2/win32/
/*  -*- LPC -*-  */
/*
 * $Id: modified_efuns.c,v 1.51 2001/04/04 18:12:20 ceres Exp wodan $
 */
#define MAX_SIZE 50000
#define LIV "/obj/handlers/livings"
// This define figures out the filename to log to.
#define LOG_NAME(X) ((X[0] == '/') ? X : "/log/"+X)

#include <login.h>
#include <player_handler.h>
#include <playtesters.h>

inherit "/secure/simul_efun/base_name";

string back_trace();

#if !efun_defined(event)
void event(mixed,string,mixed ...);
#endif

#if !efun_defined(add_action)
int _notify_fail(string);
int living(object ob);
object find_player(string);
#endif


private nosave int _callouttime;
private nosave mapping _calloutfunc = ([]);
private nosave mapping _log_file_info = ([ ]);
private nosave mapping _db_fds = ([ ]);
private nosave mapping _db_obs = ([ ]);
private nosave int _log_file_flush_id;
private nosave string _reset_eval_message="simul_efun updated";
private nosave int _reset_eval_message_count=1;
private nosave int _in_reference_allowed;

// Every 15 seconds.
#define DELAY_LOG_FLUSH 15

/**
 * Cotains some simul_efuns.
 * @author Pinkfish
 */
/**
 * @ignore yes
 */
varargs void say(string str, mixed avoid)
{
  if (!pointerp(avoid)) {
    avoid = ({ this_player(), previous_object() }) + ({ avoid });
  } else {
    avoid += ({ this_player(), previous_object() });
  }
  if (!environment(previous_object())) {
    if(this_player() && environment(this_player())) {
      event(environment(this_player()), "say", str, avoid);
    } else {
      event(previous_object(), "say", str, avoid);
    }
  } else {
    if (environment(environment(previous_object()))) {
      event(environment(environment(previous_object())), "say", str, avoid);
    } else {
      event(environment(previous_object()), "say", str, avoid);
    }
  }
} /* say()*/

/**
 * @ignore yes
 */
varargs void tell_room(mixed ob, string str, mixed avoid) {
  if (!ob || !(objectp(ob) || stringp(ob))) {
    return ;
  }
  if (stringp(ob)) {
    ob = load_object(ob);
  }
  event(ob, "say", str, avoid);
} /* tell_room() */

/**
 * @ignore yes
 */
void tell_object(object ob, string str) {
  if (objectp(ob)) {
    ob->do_efun_write( str );
  }
} /* tell_object() */

/**
 * This method is used to test to see if a reference is allowed to this
 * object.  It tests things like the allow array and that sort of stuff.
 * @param thing the object to test
 * @return 1 if the reference is allowed
 */
varargs int reference_allowed(object referree, mixed referrer) {
  string referrer_name;
  string *allowed;
  object referrer_obj;
  int ret, invis;
  
  if(!referree)
    return 0;

  invis = (int)referree->query_invis();
  if(!invis || !referree->query_creator() || _in_reference_allowed)
    return 1;

  _in_reference_allowed = 1;
  
  if(!referrer)
    referrer = this_player();
  
  if (objectp(referrer)) {
    if(!referrer || (referree == referrer)) {
      _in_reference_allowed = 0;
      return 1;
    }
    referrer_name = referrer->query_name();
    referrer_obj = referrer;
  } else if (stringp(referrer)) {
    referrer_name = referrer;
    referrer_obj = find_player(referrer);
  } else {
    _in_reference_allowed = 0;
    return 0;
  }
  
  if(!referrer_name) {
    _in_reference_allowed = 0;
    return 1;
  }
  
  allowed = (string *)referree->query_allowed();
  if ( pointerp( allowed ) ) {
    if ( member_array( referrer_name, allowed ) != -1 ||
         (member_array("playtesters", allowed) != -1 &&
          PLAYTESTER_HAND->query_playtester(referrer_name))) {
      _in_reference_allowed = 0;
      return 1;
    }
  }
  switch(invis) {
  case 3 :
    ret = master()->high_programmer( referrer_name );
    break;
  case 2 :
    ret = master()->query_lord( referrer_name );
    break;
  case 1 :
    if(referrer_obj)
      ret = referrer_obj->query_creator();
    else
      ret = PLAYER_HANDLER->test_creator( referrer_name );
    break;
  default :
    ret = 1;
  }
  _in_reference_allowed = 0;
  return ret;
}

/**
 * @ignore yes
 */
object find_living( string word ) {
   object thing;

   if ( !word ) {
      return 0;
   }
#if efun_defined(find_living)
   thing = efun::find_living( word );
#else
   thing = LIV->find_living( word );
#endif
   if ( !thing || !this_player() ) {
      return thing;
   }
   if ( reference_allowed( thing ) ) {
      return thing;
   }
   return 0;
} /* find_living() */

/**
 * @ignore yes
 */
object find_player( string word ) {
   object thing;

   if ( !word ) {
      return 0;
   }
#if efun_defined(find_player)
   thing = efun::find_player( word );
#else
   thing = LIV->find_player( word );
#endif
   if ( !thing || !this_player() ) {
      return thing;
   }
    if ( reference_allowed( thing ) && thing->query_property( "player" ) ) {
      return thing;
   }
   return 0;
} /* find_player() */

/**
 * @ignore yes
 */
object *users() {
   if ( !this_player() || ( previous_object() == master() ) ||
         ( previous_object() == find_object( "/obj/shut" ) ) ||
         ( previous_object() == find_object( "/obj/handlers/livings") ) ) {
      return efun::users();
   }
   return filter( efun::users(), (: reference_allowed :) );
} /* users() */

/** @ignore yes */
object *named_livings() {
#if efun_defined(named_livings)
  return filter( efun::named_livings(), (: reference_allowed :) );
#else
  return filter( LIV->named_livings(), (: reference_allowed :) );
#endif
} /* named_livings() */

/** @ignore yes */
object *children(string name) {
   if (strsrch(name, "global/lord") != -1) {
      return filter( efun::children(name), (: reference_allowed :) );
   }
   return efun::children(name);
} /* children() */

/**
 * This method calls an event on all the users online.  
 * It does not do any filtering, so it will send messages to people who
 * are earmuffed and ignoring or lord invisible or whatever.
 *
 * @param from the person it is from
 * @param name the name of the event
 * @param args the arguments to the event
 */
void user_event( mixed from, mixed first, mixed args ... ) {
   if ( stringp( from ) ) {
      call_other( efun::users(), "event_"+ from, previous_object(),
            first, args ... );
   } else {
      if ( objectp( from ) && stringp( first ) ) {
         call_other( efun::users(), "event_"+ first, from, args ... );
      }
   }
/*
   event( efun::users(), first, args ... );
*/
} /* user_event() */

mixed unguarded(function f);

/**
 * This method flushes out all the buffered stuff for the log files.
 */
void flush_log_files() {
   string fname;
   string data;

   _log_file_flush_id = 0;
   foreach (fname, data in _log_file_info) {
      if (file_size(LOG_NAME(fname)) > MAX_SIZE) {
         unguarded((: rm, LOG_NAME(fname)+".old" :));
         unguarded((: rename, LOG_NAME(fname), LOG_NAME(fname)+".old" :));
      }
      map_delete(_log_file_info, fname);
      unguarded((: write_file, LOG_NAME(fname), data :));
   }
   _log_file_info = ([ ]);
} /* flush_log_files() */

/**
 * This method writes a message out ot a log file.  The log files are
 * normally in "/log".  If a file doesn't start with '/ then "/log/" will be
 * preppended to it.
 * This does automatic removal of the log files after they get over
 * a certain length.  The fmt and args parameters are used to print the
 * actual message.
 * <p>
 * If more than one argument is passed to this function, then sprintf will
 * be used to print out the results.
 * <p>
 * ie: log_file("ROGER", "%s: frog and %s\n", ctime(time()), query_gumboot());
 *
 * @param name the name of the log file
 * @param fmt the format string
 * @param args the arguments to the sprintf
 */
varargs void log_file(string name, string fmt, mixed *args ...) {
  /* five screens */
  if ( strlen( fmt ) > 8000 ) { /* five screens */
    fmt = fmt[ 0 .. 7999 ] +"\n\nPlus more...\n\n";
  }
  fmt = terminal_colour(fmt, ([]));
  if (!_log_file_flush_id) {
     _log_file_flush_id = call_out((: flush_log_files :), DELAY_LOG_FLUSH);
  }
  if (!_log_file_info[name]) {
     _log_file_info[name] = "";
  }
  if (sizeof(args)) {
    _log_file_info[name] += sprintf(fmt, args ...);
  } else {
    _log_file_info[name] += fmt;
  }
} /* log_file() */

#ifdef MUD_NAME
/**
 * This method returns the name of the mud.
 *
 * @return the name of the mud
 */
string mud_name() {
  return capitalize(MUD_NAME);
} /* mud_name() */
#endif

/**
 * Write the file out to the screen.  This should  not be used if possible.
 * It is an interface to read_file and other things.  You should perhaps
 * look at using more_string ort more_file.
 *
 * @param file the file name to cat
 * @param start_line the line to start on
 * @param number the number of lines to print
 *
 * @see /global/more_string->more_string()
 * @see /global/more_file->more_file()
 */
void cat(string file, int start_line, int number) {
  string bing;

  bing = read_file(file, start_line, number);
  if (bing) {
    printf("%s", bing[0..5000]);
  }
} /* cat() */

#ifdef NEW_DRIVER
/**
 * This method tells us if the object is a wizard.
 *
 * @return is the object a wizard
 */
int wizardp(mixed arg) {
  if (!objectp(arg)) {
    return 0;
  }
  return interactive(arg) && arg->query_creator();
} /* wizardp() */
#endif

/**
 * @ignore yes
 */
int exec(object to, object from) {
  string s;
  object prev;

  if (file_name(previous_object())[0..12] == "/secure/login") {
    return efun::exec(to, from);
  }

  s = "";

  if (prev = this_player()) {
    s += "TP:"+ sprintf("%8s ", prev -> query_name());
  }

  if (prev = this_player(1)) {
    s += "TP1:"+ sprintf("%8s ", prev -> query_name());
  }

  s += "PO:"+ sprintf("%8s ", file_name(previous_object()));

  log_file("ILLEGAL", "Exec: %-40s : %s\n", s, ctime( time() ) );

  return 0;
} /* exec() */

/**
 * @ignore yes
 */

varargs int call_out(mixed fun, int delay, mixed *args ...) {
  string func;
  function wrap = function(mixed func, mixed *args) {
    int t = real_time();
    if(stringp(func)) {
      call_other(this_object(), func, args ...);
    } else if(functionp(func)) {
      evaluate(func, args ...);
    }
    if((real_time() - t) > 1) {
      "/secure/simul_efun"->tell_creator("wodan", " %d ");
    }
  };

  wrap = bind(wrap, previous_object());
  
  if (_callouttime != time()) {
    _callouttime = time();
    _calloutfunc = ([]);
  }
  
  if(delay == 0) {
    func = functionp(fun)?""+functionp(fun):fun +
      file_name(previous_object());
    if(_calloutfunc[func] == -1)
      delay = 2;
    else if(++_calloutfunc[func] > 100) {
      delay = 2;
      _calloutfunc[func] = -1;
      if ( stringp(previous_object()->query_name())) {
        log_file("CALL_OUT_LOG", ctime(time()) + ": " +
                 "Object %O (%s) seems to loop in function %O.\n",
                 previous_object(), previous_object()->query_name(), fun);
      } else {
        log_file("CALL_OUT_LOG", ctime(time()) + ": " +
                 "Object %O (%s) seems to loop in function %O.\n",
                 previous_object(), fun);
      }
    }
  }

  return evaluate(bind((: efun::call_out($(wrap), $(delay), $(fun), $(args)) :)
                       , previous_object()));

} /* call_out() */

/**
 * This returns the current verb name.  This works if the verb ius used
 * through add_command or through add_action.
 *
 * @return the name of the verb
 */
string query_verb() {
   string verb;
#if efun_defined(query_verb)
   verb = efun::query_verb();
#else
   verb = "";
#endif
   if ( ( verb != "" ) || !objectp( this_player() ) ) {
      return verb;
   }
   return (string)this_player()->query_current_verb();
} /* query_verb() */

/**
 * Does a string compare...  But case insensative...
 *
 * @param str1 the string to compare
 * @param str2 the other string to compare
 * @return 0 if they are the same, <0 if they are less than each other, >0 if not
 * @see efun::strcmp()
 */
int strcasecmp(string str1, string str2) {
  return strcmp(lower_case(str1), lower_case(str2));
} /* strcasecmp() */

#define COMPAT_TAIL
#ifdef COMPAT_TAIL
/* This version is strictly compatible with the old version */
/**
 * This will print the last bit of a file.
 * @param fname the file to read
 * @return 1 if it succeeded, 0 if it failed
 */
int tail(string fname) {
   int offset = file_size(fname);
   string str;

   if (offset < 0) {
      return 0;
   }
     
   offset -= 54 * 20;
   if (offset < 0) {
      offset = 0;
   }
   str = read_bytes(fname, offset, 1080);
   if (!str) {
      return 0;
   }
   if (offset) {
      str = str[strsrch(str, "\n")+1..];
   }
   write(str);

   return 1;
} /* tail() */
#else
/* This version is slightly extended and compatible in spirit, but doesn't
 * reproduce the oddities of the original tail() efun.  Note that it also
 * returns the string, so write(tail(fname)) is needed for strict 
 * compatibility.
 */
/**
 * This will print the last bit of a file.
 * @param fname the file to read
 * @return 1 if it succeeded, 0 if it failed
 */
varargs string tail(string fname, int nlines) {
    int chunk = nlines * 80;
    int offset = file_size(fname);
    int num_nl, p, skip;
    string str = "";

    reset_eval_cost();
    while (offset > 0 && num_nl <= nlines) {
  num_nl = 0;
  offset -= chunk;
  if (offset < 0) {
      chunk += offset; /* negative */
      offset = 0;
  }
  str = read_bytes(fname, offset, chunk) + str;
  p = -1;
  while (p < sizeof(str)-1 && p = member_array('\n', str, p+1))
      num_nl++;
    }
    skip = num_nl - nlines;
    p = -1;
    while (skip--)
  p = member_array('\n', str, p+1);
    return str[p..];
}
#endif

/**
 * This method prints a message to the player.
 * @param str the message to send
 */
void write(mixed str) {
  if (!this_player()) {
    return ;
  }
  if (intp(str)) {
    str = ""+str;
  }
  this_player()->do_efun_write(str);
} /* write() */

/** @ignore yes */
int notify_fail( mixed stuff ) {
   if (!this_player())  {
      return 0;
   }
   if ( functionp( stuff ) ) {
      stuff = evaluate( stuff );
   }
   if ( !stringp( stuff ) ) {
      return 0;
   }
   this_player()->print_messages();
   stuff = (string)this_player()->convert_message( stuff );
   /* for observer-dependent shorts */
   stuff = (string)this_player()->fit_message( stuff );
   /* for capitalisation and indentation */
   stuff = (string)this_player()->fix_string( stuff );
   /* for colour */
#if efun_defined(notify_fail)
   return efun::notify_fail( stuff );
#else
   return _notify_fail( stuff );
#endif
} /* notify_fail() */

/**
 * Replaces all occurances of a set of strings in the input string.  Replaces
 * an individual or an array of strings with new values.  If the second
 * argument is an array of strings, then the 1st, 3rd, 5th...  elements will
 * be the strings to search for and the 2nd, 4th, 6th etc will be the strings
 * to replace with.  If three arguments are specified then the second is the string
 * to search for, the third the one to replace.
 * <p>
 * Eg:<br>
 * str = replace(str, ({ "search", "replace", "orange", "apple" });<p>
 * That will replace all occurances of "search" with "replace" and "orange"
 * with "apple".
 *
 * @param str the string to do the replacement in
 * @param bing the search or array argument
 * @param rep the replacement string, or null
 *
 * @return the string with all the replacements done
 */
varargs string replace(string str, mixed bing, string rep) {
  int i;

  if (pointerp(bing)) {
    for (i=0;i<sizeof(bing);i+=2) {
      if (stringp(bing[i]) && stringp(bing[i+1])) {
        str = replace_string(str, bing[i], bing[i+1]);
      }
    }
    return str;
  }
  if(!stringp(str) || !stringp(rep))
    return str;
  return replace_string(str, bing, rep);
} /* replace() */

/**
 * This method returns a string with each word capitalized.
 *<p>
 * @param words the string to capitalize
 * @return the string with all words capitalized
 */
string cap_words(string words)  {
  return implode(map(explode(words, " "), (: capitalize :)), " ");
}


/**
 * This method will return an array that contains no duplicates.
 *  uniq_array.c
 *  Written by: Wodan
 * <p>
 *  This function will return an array that contains no duplicates.
 *  Gotta love them mappings. :)
 * @param arr the array to convert
 * @return an array with no duplicates
 */
mixed *uniq_array(mixed *arr){
  return keys(allocate_mapping(arr, 1));
} /* uniq_array() */

/**
 * This method sends a polite shout to everyone on line.  It checks
 * for earmuffs and all that sort of stuff.
 * @param words the message to shout
 * @param avoid who not to tell the message to
 */
varargs void shout( string words, object avoid ) {
   object thing, *things;
   things = efun::users();
   foreach( thing in things ) {
      if ( thing && ( thing != avoid ) && !thing->check_earmuffs( "shout" ) ) {
         if ( thing != this_player() ) {
            thing->event_say( previous_object(), words, ({ }) );
         }
      }
   }
} /* shout() */

 /** @ignore yes */
void reset_eval_cost() {
   //string new_reset_eval_message;

   //_new_reset_eval_message = sprintf("%s: reset_eval_cost() called in %O",
                                    //ctime(time()), previous_object());
   //if ( !strcmp(_new_reset_eval_message, _reset_eval_message) ) {
      //_reset_eval_message_count++;
   //} else {
//     log_file("RESET_EVAL_COST", sprintf("%s %i time(s).\n",
//                                          reset_eval_message,
//                                          reset_eval_message_count ));
      //_reset_eval_message_count = 1;
      //_reset_eval_message = new_reset_eval_message;
   //}
   efun::reset_eval_cost();
} /* reset_eval_cost() */

#if !efun_defined(event)
/** @ignore yes */
varargs int member_array(mixed item, mixed arr, int start, int flag){
  if(!flag)
    return efun::member_array(item, arr, start);
  if(stringp(item)){
    string *tmp;
    tmp = map(arr, (:$1[0..$(strlen(item)-1)]:));
    return efun::member_array(item, tmp, start);
  }
}

/** @ignore yes */
void event(mixed ob, string func, mixed rest ...){
  object origin = previous_object(), *bing;
  string name = "event_" + func;
  if(arrayp(ob)){
    ob = filter(ob, (:$1:));
    call_other(ob, name, origin, rest ...);
    return;
  } else if(!objectp(ob)) {
    return;
  }
  
  call_other(ob, name, origin, rest ...);
  bing = all_inventory(ob);
  bing -= ({origin});
  bing = filter(bing, (:$1:));
  call_other(bing, name, origin, rest ...);
}

#endif

#if !efun_defined(add_action)
/** @ignore yes */
void move_object(mixed ob){
  object tp, *obs, bing;

  if(stringp(ob)) {
    ob = find_object(ob);
  }

  evaluate(bind((: efun::move_object($(ob)):), previous_object()));

  if(ob->no_init()){
    return;
  }
  
  tp = this_player();

  if(living(previous_object())){
    efun::set_this_player(previous_object());
    ob->init();
    (all_inventory(ob) - ({previous_object()}))->init();
  }
  
  obs = filter(all_inventory(ob),
               (:living($1) && $1 != $(previous_object()):));
  foreach(bing in obs){
    efun::set_this_player(bing);
    previous_object()->init();
  }
  
  if(living(ob)){
    efun::set_this_player(ob);
    previous_object()->init();
  }
    
  efun::set_this_player(tp);
}
#endif

#if efun_defined(db_exec)
/** @ignore yes */
varargs mixed db_exec(int fd, string fmt, mixed *args ...) {
  _db_fds[fd] = time();
  if (!sizeof(args)) {
    return efun::db_exec(fd, fmt);
  } else {
    return efun::db_exec(fd, sprintf(fmt, args ...));
  }
}

varargs int db_connect(mixed *args ...){
  int fd;
  string ob = file_name(previous_object());
  switch(sizeof(args)){ //gnaaaaaa
  case 0:
  case 1:
    error("Not enough arguments to db_connect.");
  case 2:
    fd = efun::db_connect(args[0], args[1]);
    break;
  case 3:
    fd = efun::db_connect(args[0], args[1], args[2]);
    break;
  default:
    fd = efun::db_connect(args[0], args[1], args[2], args[3]);
  }
    
  _db_fds[fd] = time();
  _db_obs[fd] = ob;
  if(sizeof(keys(filter(_db_obs, (:$2 == $(ob):)))) > 3){
    log_file("FDS", "file: %s\n", ob);
  }
  return fd;
}

mixed *db_fetch(int fd, int row){
  _db_fds[fd] = time();
  return efun::db_fetch(fd, row);
}

void db_close(int fd){
  map_delete(_db_fds, fd);
  map_delete(_db_obs, fd);
  efun::db_close(fd);
}

string db_fds(){
  int *fds = keys(_db_fds);
  return implode(fds, (:$1 + sprintf("fd: %d   time: %s   object: %s\n",
                                     $2, ctime($(_db_fds)[$2]),
                                     $(_db_obs)[$2]):), "");
}

#else
varargs int db_connect(mixed *args ...){
  error("No database installed");
}

/** @ignore yes */
varargs string db_exec(int fd, string fmt, mixed *args ...) {
  return "No database installed";
}

/** @ignore yes */
mixed *db_fetch(int fd, int row){
  error("No database installed");
}

/** @ignore yes */
void db_close(int fd){}
#endif

/** @ignore yes */
void shutdown(int bing){
  string thing = base_name(previous_object());
  if(thing != "/obj/shut" && thing != "/global/lord"){
    unguarded((:write_file, "/d/admin/log/SHUTDOWN.log",
               sprintf("value %d\n%s", bing, back_trace()):));
  }
  efun::shutdown(bing);
}

/** @ignore yes */
#if !efun_defined(real_time)
int real_time(){return time();}
#endif

#if efun_defined(memory_summary)
string memory_summary() {
   return "Not on this mud...\n";
} /* memory_summary() */
#endif

/**
 * Debug info Simul Efun
 * @author Terano
 * @started 17/8/00
 * To fix gaping security holes.
 */

#if efun_defined(debug_info)
string debug_info( int operation, object ob ) {

  string path;

  if ( operation != 2 )
    return efun::debug_info( operation, ob );
  
  path = base_name( ob );
  path += ".c";

  if ( !master()->valid_read( path,
                              this_player()->query_name(), "debug_info" ) ) {
    this_object()->unguarded((:write_file, "/d/admin/log/DEBUG_INFO.log",
                sprintf( "%s: %s tried to debug %s.\n", ctime( time() ),
                         this_player()->query_name(),
                         base_name( ob ) ) :));
    return "You are not authorised to do that.\n";
  }
  if ( interactive( ob ) && !this_player()->query_lord() &&
       ob != this_player()) {
    this_object()->unguarded((:write_file, "/d/admin/log/DEBUG_INFO.log",
                sprintf( "%s: %s tried to debug %s.\n", ctime( time() ),
                         this_player()->query_name(),
                         ob->query_name() ) :));
    return "Only Lords can dump an interactive object.\n";
  }
  return efun::debug_info( operation, ob );
}

#endif

varargs int new_call_out(mixed fun, int delay, mixed *args ...) {
  string func;
  function wrap = function(mixed func, mixed *args) {
    int t = real_time();
    if(stringp(func)) {
      call_other(this_object(), func, args ...);
    } else if(functionp(func)) {
      evaluate(func, args ...);
    }
    if((real_time() - t) > 1) {
      "/secure/simul_efun"->tell_creator("wodan", " %d ");
    }
  };

  wrap = bind(wrap, previous_object());
  
  if (_callouttime != time()) {
    _callouttime = time();
    _calloutfunc = ([]);
  }
  
  if(delay == 0) {
    func = functionp(fun)?""+functionp(fun):fun +
      file_name(previous_object());
    if(_calloutfunc[func] == -1)
      delay = 2;
    else if(++_calloutfunc[func] > 100) {
      delay = 2;
      _calloutfunc[func] = -1;
      if ( stringp(previous_object()->query_name())) {
        log_file("CALL_OUT_LOG", ctime(time()) + ": " +
                 "Object %O (%s) seems to loop in function %O.\n",
                 previous_object(), previous_object()->query_name(), fun);
      } else {
        log_file("CALL_OUT_LOG", ctime(time()) + ": " +
                 "Object %O (%s) seems to loop in function %O.\n",
                 previous_object(), fun);
      }
    }
  }
  

  return evaluate(bind((: efun::call_out($(wrap), $(delay), $(fun), $(args)) :)
                       , previous_object()));
}