lima-1.0b5/
lima-1.0b5/driver/
lima-1.0b5/driver/ChangeLog.old/
lima-1.0b5/driver/Win32/
lima-1.0b5/driver/compat/
lima-1.0b5/driver/include/
lima-1.0b5/driver/testsuite/
lima-1.0b5/driver/testsuite/clone/
lima-1.0b5/driver/testsuite/command/
lima-1.0b5/driver/testsuite/data/
lima-1.0b5/driver/testsuite/etc/
lima-1.0b5/driver/testsuite/include/
lima-1.0b5/driver/testsuite/inherit/
lima-1.0b5/driver/testsuite/inherit/master/
lima-1.0b5/driver/testsuite/log/
lima-1.0b5/driver/testsuite/single/
lima-1.0b5/driver/testsuite/single/tests/compiler/
lima-1.0b5/driver/testsuite/single/tests/efuns/
lima-1.0b5/driver/testsuite/single/tests/operators/
lima-1.0b5/driver/testsuite/u/
lima-1.0b5/driver/tmp/
lima-1.0b5/etc/
lima-1.0b5/lib/WWW/help/
lima-1.0b5/lib/cmds/
lima-1.0b5/lib/cmds/create/
lima-1.0b5/lib/cmds/player/attic/
lima-1.0b5/lib/contrib/bboard/
lima-1.0b5/lib/contrib/boards/
lima-1.0b5/lib/contrib/marriage/
lima-1.0b5/lib/contrib/roommaker/
lima-1.0b5/lib/contrib/transient_effect/
lima-1.0b5/lib/daemons/channel/
lima-1.0b5/lib/daemons/imud/
lima-1.0b5/lib/data/
lima-1.0b5/lib/data/config/
lima-1.0b5/lib/data/links/
lima-1.0b5/lib/data/news/
lima-1.0b5/lib/data/players/
lima-1.0b5/lib/data/secure/
lima-1.0b5/lib/domains/
lima-1.0b5/lib/domains/std/2.4.5/maze1/
lima-1.0b5/lib/domains/std/2.4.5/npc/
lima-1.0b5/lib/domains/std/2.4.5/post_dir/
lima-1.0b5/lib/domains/std/2.4.5/sub/
lima-1.0b5/lib/domains/std/camera/
lima-1.0b5/lib/domains/std/config/
lima-1.0b5/lib/domains/std/cult/
lima-1.0b5/lib/domains/std/effects/
lima-1.0b5/lib/domains/std/misc/
lima-1.0b5/lib/domains/std/monsters/
lima-1.0b5/lib/domains/std/recorder/
lima-1.0b5/lib/domains/std/rooms/
lima-1.0b5/lib/domains/std/rooms/beach/
lima-1.0b5/lib/domains/std/rooms/labyrinth/
lima-1.0b5/lib/domains/std/school/
lima-1.0b5/lib/domains/std/school/O/
lima-1.0b5/lib/domains/std/spells/
lima-1.0b5/lib/domains/std/spells/stock-mage/
lima-1.0b5/lib/domains/std/spells/stock-priest/
lima-1.0b5/lib/help/
lima-1.0b5/lib/help/admin/
lima-1.0b5/lib/help/hints/General_Questions/
lima-1.0b5/lib/help/hints/Pirate_Quest/
lima-1.0b5/lib/help/player/
lima-1.0b5/lib/help/player/bin/
lima-1.0b5/lib/help/player/quests/
lima-1.0b5/lib/help/wizard/
lima-1.0b5/lib/help/wizard/coding/guilds/
lima-1.0b5/lib/help/wizard/coding/rooms/
lima-1.0b5/lib/help/wizard/lib/daemons/
lima-1.0b5/lib/help/wizard/lib/lfun/
lima-1.0b5/lib/help/wizard/lib/std/
lima-1.0b5/lib/help/wizard/mudos_doc/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/interactive/
lima-1.0b5/lib/help/wizard/mudos_doc/applies/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/concepts/
lima-1.0b5/lib/help/wizard/mudos_doc/driver/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/arrays/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/buffers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/compile/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/filesystem/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/floats/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/functions/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/general/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mappings/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/mixed/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/numbers/
lima-1.0b5/lib/help/wizard/mudos_doc/efuns/parsing/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/constructs/
lima-1.0b5/lib/help/wizard/mudos_doc/lpc/types/
lima-1.0b5/lib/include/driver/
lima-1.0b5/lib/log/
lima-1.0b5/lib/obj/admtool/
lima-1.0b5/lib/obj/admtool/internal/
lima-1.0b5/lib/obj/admtool/mudinfo/
lima-1.0b5/lib/obj/admtool/secure/
lima-1.0b5/lib/obj/secure/
lima-1.0b5/lib/obj/secure/cmd/
lima-1.0b5/lib/obj/secure/mailers/
lima-1.0b5/lib/obj/secure/shell/
lima-1.0b5/lib/obj/secure/shell/classes/
lima-1.0b5/lib/obj/tasktool/
lima-1.0b5/lib/obj/tasktool/internal/
lima-1.0b5/lib/open/
lima-1.0b5/lib/secure/
lima-1.0b5/lib/secure/cgi/
lima-1.0b5/lib/secure/modules/
lima-1.0b5/lib/secure/simul_efun/
lima-1.0b5/lib/std/adversary/
lima-1.0b5/lib/std/adversary/advancement/
lima-1.0b5/lib/std/adversary/armor/
lima-1.0b5/lib/std/adversary/blows/
lima-1.0b5/lib/std/adversary/death/
lima-1.0b5/lib/std/adversary/formula/
lima-1.0b5/lib/std/adversary/health/
lima-1.0b5/lib/std/adversary/pulse/
lima-1.0b5/lib/std/adversary/wield/
lima-1.0b5/lib/std/classes/event_info/
lima-1.0b5/lib/std/container/
lima-1.0b5/lib/std/living/
lima-1.0b5/lib/std/modules/contrib/
lima-1.0b5/lib/std/patterns/
lima-1.0b5/lib/std/race/
lima-1.0b5/lib/std/race/restricted/
lima-1.0b5/lib/std/room/
lima-1.0b5/lib/tmp/
lima-1.0b5/lib/trans/
lima-1.0b5/lib/trans/admincmds/
lima-1.0b5/lib/trans/obj/
lima-1.0b5/lib/wiz/
/* Do not remove the headers from this file! see /USAGE for more info. */

#include <driver/type.h>

string evaluate_path(string);
object find_body(string);
object this_body();
private nosave string array normal_directions = ({ "up", "down",
                                                   "north", "northeast",
                                                   "northwest", "east",
                                                   "southeast", "southwest",
                                                   "south", "west" });

//FUNCTION is_normal_direction
//returns 1 if the direction is 'normal'
int
is_normal_direction(string dir) {
     if (member_array(dir, normal_directions) != -1)
         return 1;
     return 0;
}

//:FUNCTION call_trace
//returns the stack of objects and functions

string
call_trace() {
    string res;
    int i, n;
    object array objects;
    string array programs;
    string array functions;
    
    res = "";
    programs = call_stack(0);
    objects = call_stack(1);
    functions = call_stack(2);

    n = sizeof(programs);
    for (i = 0; i < n; i++) {
	res += sprintf("%25-O %25-s %25-s\n", objects[i], programs[i], 
		       functions[i]);
    }
    return res;
}

// There should be an | operator for this.

//:FUNCTION clean_array
//returns a version of the passed array with duplicate
//entries removed.  Eg, clean_array(({1,2,2}))  => ({1,2})
mixed*
clean_array(mixed* r) {
    int i, n;

    r = r & r; // sort.  sort_array() can't hack it.  And no, &= doesn't work.

    n = sizeof(r) - 1;
    while (i < n) {
	if (r[i] == r[i+1]) {
	    int j = i+1;
	    
	    while (j < n && r[i] == r[j + 1])
		j++;

	    r[i..j-1] = ({});
	    n -= j - i;
	}
	i++;
    }

    return r;
}

//:FUNCTION rev_explode
//returns a reversable explode, because sometimes this has a desired
//effect.  This sefun requires SANE_EXPLODE_STRING to work properly 
//but the mudlib already requires that anyway.
string array rev_explode(string arr_in, string delim)
{
  string array arr_out=({});
  if(arr_in[0..strlen(delim)-1]==delim)
    arr_out=({""});
  arr_out+=explode(arr_in,delim);
  if(arr_in[<strlen(delim)..]==delim)
    arr_out+=({""});
  return arr_out;
}

//:FUNCTION abs
// Absolute value function
int abs(int x)
{
   return x < 0 ? -x : x;
}


//:FUNCTION cmp
//returns whether its two arguments are equivalent.  This is about
//the same as using the equivalence operator (==), but will return true
//in cases where == does not, such as when comparing 2 arrays.
//Logically 2 arrays should be equivalent, but aren't with ==.
//cmp knows they are.  This is mainly useful when you want to compare
//mappings and arrays.

int cmp( mixed a, mixed b )
{
  int		i;
  mixed		x, y, z;

  if( arrayp( a ) && arrayp( b ) )
  {

    if( sizeof(a) != ( i = sizeof(b) ) )
      return 0;

    while( i-- )
      if( !cmp(a[i], b[i]) )
        return 0;
    return 1;
  }

  if( mapp( a ) && mapp( b ) )
  {

    if( sizeof(a) != (i = sizeof(b)) )
      return 0;

    foreach (x,y in a) {
	z = b[x];
	if (undefinedp(z)) return 0;
	if (!cmp(y, z))
	    return 0;
    }
    return 1;
  }

  return a == b;
}


//:FUNCTION insert
//Inserts the contents of the array of the first argument into
//The array in the second argument before the nth element of the array,
//where n is the 3rd argument passed to insert.

// Rust hacked at this to make it a bit more intuitive...

mixed insert( mixed 	to_insert,
	mixed	into_array,
	int	where )
{
//### (db) I don't see any particular need to program defensively...
#if 0
  if( !arrayp( to_insert ) )
    return (void)error("Bad type arg 1 to simul efun insert()");

  if( !arrayp( into_array ) )
    return (void)error("Bad type arg 2 to simul efun insert()");

  if( !intp( where ) )
    return (void)error("Bad type arg 3 to simul efun insert()");
#endif

  return into_array[0..where-1] + to_insert + into_array[where..];
}


string parse_ref(string Ref)
{
// If the first thing is a period, we can ignore it.
    string s = Ref[0] == '.' ? Ref[1..] : Ref;
    string result;
    string noun;
    string* pieces = explode(s,":");

    noun = pieces[0];
    pieces = pieces[1..];
    switch ( noun )
    {
    case "me":
	result = "this_body()";
	break;

    case "here":
	result = "environment(this_body())";
	break;

    default:
	if ( find_body(noun) )
	    result = "find_body(\""+noun+"\")";
	else if ( load_object(evaluate_path(noun)) )
	    result = "find_object(evaluate_path(\""+noun+"\"))";
	else
	    return Ref;
    }

    foreach ( noun in pieces )
    {
	switch ( noun )
	{
	case "shell":
	    result = sprintf("(%s->query_shell_ob() || %s)", result, result);
	    break;

	case "link":
	    result = sprintf("(%s->query_link())",result);
	    break;

	default:
	    result = sprintf("present(\"%s\",%s)", noun, result);
	    break;
	}
    }
    return result;
}

object parse_ref_into_obj(string Ref)
{
    string 	s = Ref[0] == '.' ? Ref[1..] : Ref;
    object 	result;
    string 	noun;
    string	*pieces = explode(s,":");

    noun = pieces[0];
    pieces = pieces[1..];
    switch ( noun )
    {
    case "me":
	result = this_body();
	break;

    case "here":
	result = environment(this_body());
	break;

    default:
	if ( find_body(noun) )
	    result = find_body(noun);
	else if ( !(result = load_object(evaluate_path(noun))) )
	    return 0;
    }

    foreach ( noun in pieces )
    {
	switch ( noun )
	{
	case "shell":
	    result = result->query_shell_ob() || result;
	    break;

	case "link":
	    result = result->query_link();
	    break;

	default:
	    result = present(noun, result);
	    break;
	}
    }
    return result;
}

/* eval lets you evaluate a string as an expression.
   exec_code allows you to evaluate a string as LPC code. */
varargs mixed exec_code(string arg, string dir, string includefile)
{
// DO NOT USE UNGUARDED IN HERE
// If perms are bad, we want to fail.  Use unguarded(1, (: exec_code :))
// if really necessary -Beek
  string	file = dir + "/exec.c";
  object	tmp;
  mixed		retval;
  mixed		info;
  int		i;
  string	contents;
  
  if(tmp = find_object(file))
    destruct(tmp);

  rm(file);

  if(!stringp(arg))
    error("Bad type argument 1 to exec_code");
  info = reg_assoc(arg, ({"\\.[a-zA-Z:/\_]+"}),({0}))[0];
  for(i=0; i < sizeof(info);i++)
	{
    if(info[i][0] == '.' && strlen(info[i]) > 1 )
	    info[i] = parse_ref(info[i]);
	}
  arg = implode(info,"");

  if (strsrch(arg,";")==-1)
    arg = "return "+arg;

  contents = @END
#include <mudlib.h>
#include <security.h>
inherit M_ACCESS;
create() { set_privilege(1); }

END;
    
  if(includefile)
    contents += sprintf("\n#include \"%s\"\n", includefile);
    contents += sprintf( "mixed exec_foo(){ %s", arg );
    contents += ";}\n";
    write_file(file, contents);
    retval = file->exec_foo();
    rm(file);
    return retval;
}
    
// eval by Rust, so that you can
// convert a string to almost anything.
// bet on it being as slow as dirt, though... 

//:FUNCTION eval
//evaluates the string s as an LPC value.  Eg, if you have a string
//someonetyped in: "({1,2,3,4})"  eval returns the actual array
//({1,2,3,4}).

varargs mixed eval( string arg, string includefile )
{
    mixed	tmp;
    string	file;

    file = "/tmp/eval.c";

    if( tmp = find_object( file ) )
	destruct( tmp );
    rm(file);
    if( !stringp( arg ) )
    {
	error( "Bad type argument 1 to eval" );
	return;
    }
    if(includefile)
      write_file(file,sprintf("#include \"%s\"\n",includefile));

	
      
    if( arg == "0" ) return 0;
  
    if( tmp = to_int( arg ) )
	if(tmp + "" == arg)
	    return tmp;
    if( tmp = to_float( arg ) )
	if(tmp + "" == arg)
	    return tmp;

    if( tmp = find_object(arg) && objectp( tmp ) )
	return tmp;

    if( strlen( arg ) < 4 )
	return arg;

    write_file( file, sprintf( "mixed foo(){ return %s; }\n", arg ) );
    if( catch( tmp = file->foo() ) ) 
	return arg;

    if( tmp && !stringp(tmp) )
	return tmp;

    return arg;
}

//:FUNCTION decompose
//Takes any arrays that are elements in arr and merges 
//all of its elements as elements of arr.  Eg, decompose(({1,({2,3,}),4}))
//will return: ({1,2,3,4}).  The algorithm is not recursive, so if any of
//the arrays have arrays in them, those arrays remain intact.  Eg,
//decompose( ({1,({({2,3}),4}),5}) )  returns:({1,({2,3}),4,5}).
//See flatten_array for a recursive version.

mixed* decompose( mixed* org )
{
    int i = 0, j;

    if( !arrayp( org ) ) error("Bad type arg to decompose");
    org = copy(org);

    while (i < sizeof(org)) {
	if (arrayp(org[i])) {
	    j = sizeof(org[i]);
	    org[i..i] = org[i];
	    i += j; // skip the elements inserted
	} else i++;
    }
    return org;
}


//:FUNCTION choice
//Returns a random element of the structure passed, if that
// is an aggregate type (i.e., A string, array or mapping).

mixed choice( mixed f ){
    mixed *k;
  switch(typeof(f)){
    case STRING: return f[random(strlen(f))];
    case ARRAY: return f[random(sizeof(f))];
    case MAPPING: k = keys(f); return f[k[random(sizeof(k))]];
    default:
      error("choice of non-sequential type");
  }
}


//:FUNCTION min
//Returns the smallest element of an aggregate type (string, array,
//or mapping).

mixed min( mixed f ){
  if(stringp(f)) f = explode(f," ");
else
  if(mapp(f)) f = keys(f);

  return sort_array(f,1)[0];
}


//:FUNCTION max
//Returns the largest element of a structure that is a string,
//array or mapping.

mixed max( mixed f ){
  if(stringp(f)) f = explode(f," ");
else
  if(mapp(f)) f = keys(f);
  
  return sort_array(f,-1)[0];
}

//:FUNCTION flatten_array
//Takes a array that may contain arrays, and reduces all
//arrays so that the result is a one dimensional array

mixed
flatten_array(mixed arr)
{
    int i = 0;
    
    if (!arrayp(arr)) error("Bad argument 1 to flatten_array");
    arr = copy(arr);
    
    while (i < sizeof(arr)) {
	if (arrayp(arr[i])) {
	    arr[i..i] = arr[i];
	} else i++;
    }
    return arr;
}

//:FUNCTION call_out_chain
//Does a call_out to a list of functions, one following
//another, with each returning the delay till the next one is called.

protected void handle_chain(object ob, array funcs, array args) {
    int delay;
    if(!sizeof(funcs))
      return;
    if (stringp(funcs[0])) {
        delay = call_other(ob, funcs[0], args...);
    } else {
        delay = evaluate(funcs[0], args...);
    }
    call_out( (: handle_chain :), delay, ob, funcs[1..], args);
}

void call_out_chain(array funcs, int delay, array args...) {
    call_out( (: handle_chain :), delay, previous_object(), funcs, args);
}

mixed *my_call_outs()
{
  object p = previous_object();
  return filter_array(call_out_info(), (: $1[0] == $(p):));
}

// Beek fixed not to loop forever if exp < 0, etc
// also optimized extensively
int
pow(int num, int exp)
{
    int res;
    
    switch (exp) {
    case 0:
	if (!num) error("pow(0, 0) is undefined.\n");
	return 1;
    case 1:
	return num;
    case 2:
	return num * num;
    case 3:
	return num * num * num;

    case 4: 				// 2 multiplications, not 3
	num *= num;			// 1, 2, 4
	return num * num;

    case 5: 				// 3 multiplications, not 4
	exp = num * num; 		// 1, 2, 4, 5
	exp *= exp;
	return exp * num;

    case 6:				// 3 multiplications, not 5
	num *= num;			// 1, 2, 4, 6
	return num * num * num;

    case 7:				// 4 multiplications, not 6
	exp = num * num;		// 1, 2, 4, 6, 7
	exp *= exp * exp;
	return exp * num;
	
    case 8:				// 3 multiplications, not 7
	num *= num;			// 1, 2, 4, 8
	num *= num;
	return num * num;
	
    case 9:				// 4, not 8
	exp = num * num;
	exp *= exp;
	exp *= exp;
	return num * exp;

    case 10:				// 4, not 9
	num *= num;
	exp = num * num;
	exp *= exp;
	return exp * num;
	
    case 11:				// 5, not 10
	exp = num * num;
	res = exp * exp;
	res *= res;
	return res * num * exp;
	
    case 12:				// 4, not 11 ...
	num *= num;
	num *= num;
	exp = num * num;
	return exp * num;
	
    default:
	if (exp < 0)
	    return 0;
	// exp > 12 here ...
	switch (num) {
	case 0:
	    return 0;
	case 1:
	    return 1;
	case 2:
	    return 1 << exp;
	default:
	    // sub optimal, but pretty good
	    // O(log n) multiplications, not O(n)
	    res = 1;

	    while (exp) {
		if (exp & 1)
		    res *= num;
		num *= num;
		exp >>= 1;
	    }
	    return res;
	}
    }
}

int fuzzy_divide(int top, int bottom) {
    if (random(bottom) < (top % bottom))
	return top / bottom + 1;
    else
	return top / bottom;
}

string implode_by_arr(string array arr1, string array arr2)
{
  string 	res = "";
  int		i;

  if(sizeof(arr2) != (sizeof(arr1) + 1))
    error("second arg needs to have 1 more arg than first.\n");

  res += arr2[0];
  for(i=0;i<sizeof(arr1);i++)
    {
      res += arr1[i];
      res += arr2[i+1];
    }
  return res;
}

/* This one by cowl. */
/* Cleaned up, optimized, and extended by Beek */
/* 
 * type 0 = 3 hours 5 minutes 32 seconds
 * type 1 = 3h5m32s
 * type 2 = 3h
 * type 3 = 3h 5m 32s
 */
string convert_time(int sec, int type) {
    int weeks, days, hours, minutes, seconds;
    string ret;

    minutes=sec/60;
    seconds=sec-(minutes*60);
    hours=minutes/60;
    minutes=minutes-(hours*60);
    days=hours/24;
    hours=hours-(days*24);
    weeks=days/7;
    days=days-(weeks*7);

    ret = "";
    switch (type) {
    case 0:
        if(weeks) ret += M_GRAMMAR->number_of(weeks, "week") + " ";
        if(days) ret += M_GRAMMAR->number_of(days, "day") + " ";
        if(hours) ret += M_GRAMMAR->number_of(hours, "hour") + " ";
        if(minutes) ret += M_GRAMMAR->number_of(minutes, "minute") + " ";
	if (seconds && ret != "") ret += "and ";
	if (seconds) ret += M_GRAMMAR->number_of(seconds, "second") + " ";
	ret = ret[0..<2];
	break;
    case 1:
        if (weeks) ret += weeks+"w"; 
        if (days) ret += days+"d";
        if (hours) ret += hours+"h";
        if (minutes) ret += minutes+"m";
        if (seconds) ret += seconds+"s";
	break;
    case 2:
        if (weeks) { ret += weeks+"w"; break; }
        if (days) { ret += days+"d"; break; }
        if (hours) { ret += hours+"h"; break; }
        if (minutes) { ret += minutes+"m"; break; }
        if (seconds) { ret += seconds+"s"; break; }
	break;
    case 3:
        if (weeks) ret += weeks+"w ";
        if (days) ret += days+"d ";
        if (hours) ret += hours+"h ";
        if (minutes) ret += minutes+"m ";
        if (seconds) ret += seconds+"s ";
	ret = ret[0..<2];
	break;
    }
    return ret;
}

//:FUNCTION sort_by_value
//sort_by_value(arr, f) returns the array arr sorted in such
//a way that the elements are in increasing order, as defined by the
//value of the function f
array sort_by_value(array arr, function value_func) {
    return sort_array(arr, (: evaluate($(value_func), $1) - evaluate($(value_func), $2) :));
}

/* Replacement for the dump_socket_status() efun */
string dump_socket_status() {
  string ret = 
    "Fd    State      Mode       Local Address          Remote Address\n"
    "--  ---------  --------  ---------------------  ---------------------\n";
  foreach (array item in socket_status()) {
    ret += sprintf("%2d  %|9s  %|8s  %-21s  %-21s\n", item[0], item[1], item
		   [2], item[3], item[4]);
  }
  return ret;
}


string lima_version() { return "Lima 1.0b5"; }