skylib_mudos_v1/
skylib_mudos_v1/bin/
skylib_mudos_v1/bin/db/
skylib_mudos_v1/mudlib/banish/a/
skylib_mudos_v1/mudlib/banish/b/
skylib_mudos_v1/mudlib/banish/c/
skylib_mudos_v1/mudlib/banish/d/
skylib_mudos_v1/mudlib/banish/e/
skylib_mudos_v1/mudlib/banish/f/
skylib_mudos_v1/mudlib/banish/g/
skylib_mudos_v1/mudlib/banish/h/
skylib_mudos_v1/mudlib/banish/j/
skylib_mudos_v1/mudlib/banish/l/
skylib_mudos_v1/mudlib/banish/m/
skylib_mudos_v1/mudlib/banish/n/
skylib_mudos_v1/mudlib/banish/o/
skylib_mudos_v1/mudlib/banish/p/
skylib_mudos_v1/mudlib/banish/r/
skylib_mudos_v1/mudlib/banish/s/
skylib_mudos_v1/mudlib/banish/t/
skylib_mudos_v1/mudlib/banish/u/
skylib_mudos_v1/mudlib/banish/w/
skylib_mudos_v1/mudlib/cmds/
skylib_mudos_v1/mudlib/cmds/admin/
skylib_mudos_v1/mudlib/cmds/guild-race/
skylib_mudos_v1/mudlib/cmds/guild-race/crafts/
skylib_mudos_v1/mudlib/cmds/guild-race/magic/
skylib_mudos_v1/mudlib/cmds/guild-race/other/
skylib_mudos_v1/mudlib/cmds/living/broken/
skylib_mudos_v1/mudlib/cmds/player/group_cmds/
skylib_mudos_v1/mudlib/d/admin/
skylib_mudos_v1/mudlib/d/admin/room/
skylib_mudos_v1/mudlib/d/admin/room/we_care/
skylib_mudos_v1/mudlib/d/admin/save/
skylib_mudos_v1/mudlib/d/admin/text/
skylib_mudos_v1/mudlib/d/learning/TinyTown/buildings/
skylib_mudos_v1/mudlib/d/learning/TinyTown/map/
skylib_mudos_v1/mudlib/d/learning/TinyTown/roads/
skylib_mudos_v1/mudlib/d/learning/chars/
skylib_mudos_v1/mudlib/d/learning/functions/
skylib_mudos_v1/mudlib/d/learning/handlers/
skylib_mudos_v1/mudlib/d/learning/help_topics/
skylib_mudos_v1/mudlib/d/learning/help_topics/npcs/
skylib_mudos_v1/mudlib/d/learning/help_topics/objects/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/
skylib_mudos_v1/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/crowd/
skylib_mudos_v1/mudlib/d/learning/help_topics/rooms/situations/
skylib_mudos_v1/mudlib/d/learning/save/
skylib_mudos_v1/mudlib/d/learning/school/
skylib_mudos_v1/mudlib/d/learning/school/add_sc/
skylib_mudos_v1/mudlib/d/learning/school/characters/
skylib_mudos_v1/mudlib/d/learning/school/general/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/basic_commands/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/edtutor/
skylib_mudos_v1/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_mudos_v1/mudlib/d/learning/school/items/
skylib_mudos_v1/mudlib/d/learning/school/npc_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/
skylib_mudos_v1/mudlib/d/learning/school/room_school/room_basic/
skylib_mudos_v1/mudlib/d/learning/school/room_school/situations/
skylib_mudos_v1/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_mudos_v1/mudlib/d/learning/text/
skylib_mudos_v1/mudlib/d/liaison/
skylib_mudos_v1/mudlib/d/mudlib/
skylib_mudos_v1/mudlib/d/mudlib/changes/
skylib_mudos_v1/mudlib/d/playtesters/
skylib_mudos_v1/mudlib/d/playtesters/effects/
skylib_mudos_v1/mudlib/d/playtesters/handlers/
skylib_mudos_v1/mudlib/d/playtesters/items/
skylib_mudos_v1/mudlib/d/sage/
skylib_mudos_v1/mudlib/doc/
skylib_mudos_v1/mudlib/doc/creator/
skylib_mudos_v1/mudlib/doc/driver/
skylib_mudos_v1/mudlib/doc/driver/efuns/arrays/
skylib_mudos_v1/mudlib/doc/driver/efuns/buffers/
skylib_mudos_v1/mudlib/doc/driver/efuns/compile/
skylib_mudos_v1/mudlib/doc/driver/efuns/filesystem/
skylib_mudos_v1/mudlib/doc/driver/efuns/floats/
skylib_mudos_v1/mudlib/doc/driver/efuns/functions/
skylib_mudos_v1/mudlib/doc/driver/efuns/general/
skylib_mudos_v1/mudlib/doc/driver/efuns/mappings/
skylib_mudos_v1/mudlib/doc/driver/efuns/mixed/
skylib_mudos_v1/mudlib/doc/driver/efuns/mudlib/
skylib_mudos_v1/mudlib/doc/driver/efuns/numbers/
skylib_mudos_v1/mudlib/doc/driver/efuns/parsing/
skylib_mudos_v1/mudlib/doc/known_command/
skylib_mudos_v1/mudlib/doc/login/
skylib_mudos_v1/mudlib/doc/lpc/basic_manual/
skylib_mudos_v1/mudlib/doc/lpc/intermediate/
skylib_mudos_v1/mudlib/doc/new/add_command/
skylib_mudos_v1/mudlib/doc/new/events/
skylib_mudos_v1/mudlib/doc/new/handlers/
skylib_mudos_v1/mudlib/doc/new/living/race/
skylib_mudos_v1/mudlib/doc/new/living/spells/
skylib_mudos_v1/mudlib/doc/new/object/
skylib_mudos_v1/mudlib/doc/new/player/
skylib_mudos_v1/mudlib/doc/new/room/guild/
skylib_mudos_v1/mudlib/doc/new/room/outside/
skylib_mudos_v1/mudlib/doc/new/room/storeroom/
skylib_mudos_v1/mudlib/doc/object/
skylib_mudos_v1/mudlib/doc/playtesters/
skylib_mudos_v1/mudlib/doc/policy/
skylib_mudos_v1/mudlib/doc/weapons/
skylib_mudos_v1/mudlib/global/
skylib_mudos_v1/mudlib/global/creator/
skylib_mudos_v1/mudlib/global/handlers/
skylib_mudos_v1/mudlib/global/virtual/setup_compiler/
skylib_mudos_v1/mudlib/include/cmds/
skylib_mudos_v1/mudlib/include/effects/
skylib_mudos_v1/mudlib/include/npc/
skylib_mudos_v1/mudlib/include/room/
skylib_mudos_v1/mudlib/include/shops/
skylib_mudos_v1/mudlib/net/daemon/
skylib_mudos_v1/mudlib/net/daemon/chars/
skylib_mudos_v1/mudlib/net/inherit/
skylib_mudos_v1/mudlib/net/obj/
skylib_mudos_v1/mudlib/obj/amulets/
skylib_mudos_v1/mudlib/obj/b_day/
skylib_mudos_v1/mudlib/obj/clothes/
skylib_mudos_v1/mudlib/obj/dwarmours/plate/
skylib_mudos_v1/mudlib/obj/dwclothes/transport/horse/
skylib_mudos_v1/mudlib/obj/dwscabbards/
skylib_mudos_v1/mudlib/obj/dwweapons/axes/
skylib_mudos_v1/mudlib/obj/dwweapons/chains/
skylib_mudos_v1/mudlib/obj/faith/symbols/
skylib_mudos_v1/mudlib/obj/fungi/
skylib_mudos_v1/mudlib/obj/gatherables/
skylib_mudos_v1/mudlib/obj/instruments/
skylib_mudos_v1/mudlib/obj/magic/
skylib_mudos_v1/mudlib/obj/media/
skylib_mudos_v1/mudlib/obj/misc/player_shop/
skylib_mudos_v1/mudlib/obj/monster/godmother/
skylib_mudos_v1/mudlib/obj/monster/transport/
skylib_mudos_v1/mudlib/obj/rings/
skylib_mudos_v1/mudlib/obj/spells/
skylib_mudos_v1/mudlib/obj/stationery/
skylib_mudos_v1/mudlib/obj/stationery/envelopes/
skylib_mudos_v1/mudlib/obj/stationery/papers/
skylib_mudos_v1/mudlib/obj/toys/
skylib_mudos_v1/mudlib/obj/vessels/
skylib_mudos_v1/mudlib/obj/weapons/swords/
skylib_mudos_v1/mudlib/save/autodoc/
skylib_mudos_v1/mudlib/save/leaflets/
skylib_mudos_v1/mudlib/save/mail/
skylib_mudos_v1/mudlib/save/new_soul/data/
skylib_mudos_v1/mudlib/save/parcels/
skylib_mudos_v1/mudlib/save/playerinfo/
skylib_mudos_v1/mudlib/save/players/d/
skylib_mudos_v1/mudlib/save/random_names/
skylib_mudos_v1/mudlib/save/random_names/data/
skylib_mudos_v1/mudlib/save/terrains/
skylib_mudos_v1/mudlib/save/terrains/tutorial_desert/
skylib_mudos_v1/mudlib/save/terrains/tutorial_grassy_field/
skylib_mudos_v1/mudlib/save/terrains/tutorial_mountain/
skylib_mudos_v1/mudlib/save/todo_lists/
skylib_mudos_v1/mudlib/secure/
skylib_mudos_v1/mudlib/secure/cmds/admin/
skylib_mudos_v1/mudlib/secure/cmds/lord/
skylib_mudos_v1/mudlib/secure/config/
skylib_mudos_v1/mudlib/secure/handlers/autodoc/
skylib_mudos_v1/mudlib/secure/handlers/intermud/
skylib_mudos_v1/mudlib/secure/include/global/
skylib_mudos_v1/mudlib/secure/save/
skylib_mudos_v1/mudlib/secure/save/handlers/
skylib_mudos_v1/mudlib/secure/std/classes/
skylib_mudos_v1/mudlib/secure/std/modules/
skylib_mudos_v1/mudlib/std/commands/
skylib_mudos_v1/mudlib/std/commands/shadows/
skylib_mudos_v1/mudlib/std/creator/
skylib_mudos_v1/mudlib/std/dom/
skylib_mudos_v1/mudlib/std/effects/
skylib_mudos_v1/mudlib/std/effects/external/
skylib_mudos_v1/mudlib/std/effects/fighting/
skylib_mudos_v1/mudlib/std/effects/priest/
skylib_mudos_v1/mudlib/std/effects/room/
skylib_mudos_v1/mudlib/std/environ/
skylib_mudos_v1/mudlib/std/guilds/
skylib_mudos_v1/mudlib/std/guilds/old/
skylib_mudos_v1/mudlib/std/languages/
skylib_mudos_v1/mudlib/std/languages/BACKUPS/
skylib_mudos_v1/mudlib/std/liquids/
skylib_mudos_v1/mudlib/std/npc/
skylib_mudos_v1/mudlib/std/npc/goals/
skylib_mudos_v1/mudlib/std/npc/goals/basic/
skylib_mudos_v1/mudlib/std/npc/goals/misc/
skylib_mudos_v1/mudlib/std/npc/plans/
skylib_mudos_v1/mudlib/std/npc/plans/basic/
skylib_mudos_v1/mudlib/std/npc/types/
skylib_mudos_v1/mudlib/std/npc/types/helper/
skylib_mudos_v1/mudlib/std/npcs/
skylib_mudos_v1/mudlib/std/outsides/
skylib_mudos_v1/mudlib/std/races/shadows/
skylib_mudos_v1/mudlib/std/room/basic/topography/
skylib_mudos_v1/mudlib/std/room/controller/
skylib_mudos_v1/mudlib/std/room/inherit/topography/
skylib_mudos_v1/mudlib/std/room/topography/area/
skylib_mudos_v1/mudlib/std/room/topography/iroom/
skylib_mudos_v1/mudlib/std/room/topography/milestone/
skylib_mudos_v1/mudlib/std/shadows/curses/
skylib_mudos_v1/mudlib/std/shadows/disease/
skylib_mudos_v1/mudlib/std/shadows/fighting/
skylib_mudos_v1/mudlib/std/shadows/healing/
skylib_mudos_v1/mudlib/std/shadows/magic/
skylib_mudos_v1/mudlib/std/shadows/poison/
skylib_mudos_v1/mudlib/std/shadows/rituals/
skylib_mudos_v1/mudlib/std/shadows/room/
skylib_mudos_v1/mudlib/std/shops/controllers/
skylib_mudos_v1/mudlib/std/shops/objs/
skylib_mudos_v1/mudlib/std/shops/player_shop/
skylib_mudos_v1/mudlib/std/socket/
skylib_mudos_v1/mudlib/std/soul/
skylib_mudos_v1/mudlib/std/soul/d/
skylib_mudos_v1/mudlib/std/soul/e/
skylib_mudos_v1/mudlib/std/soul/i/
skylib_mudos_v1/mudlib/std/soul/j/
skylib_mudos_v1/mudlib/std/soul/k/
skylib_mudos_v1/mudlib/std/soul/l/
skylib_mudos_v1/mudlib/std/soul/n/
skylib_mudos_v1/mudlib/std/soul/o/
skylib_mudos_v1/mudlib/std/soul/q/
skylib_mudos_v1/mudlib/std/soul/u/
skylib_mudos_v1/mudlib/std/soul/v/
skylib_mudos_v1/mudlib/std/soul/y/
skylib_mudos_v1/mudlib/std/soul/z/
skylib_mudos_v1/mudlib/std/stationery/
skylib_mudos_v1/mudlib/w/
skylib_mudos_v1/mudlib/w/default/
skylib_mudos_v1/mudlib/w/default/armour/
skylib_mudos_v1/mudlib/w/default/clothes/
skylib_mudos_v1/mudlib/w/default/item/
skylib_mudos_v1/mudlib/w/default/npc/
skylib_mudos_v1/mudlib/w/default/room/
skylib_mudos_v1/mudlib/w/default/weapon/
skylib_mudos_v1/mudlib/www/
skylib_mudos_v1/mudlib/www/download/
skylib_mudos_v1/mudlib/www/java/
skylib_mudos_v1/mudlib/www/secure/
skylib_mudos_v1/mudlib/www/secure/lpc/advanced/
skylib_mudos_v1/mudlib/www/secure/lpc/intermediate/
skylib_mudos_v1/v22.2b14-DSv10/
skylib_mudos_v1/v22.2b14-DSv10/ChangeLog.old/
skylib_mudos_v1/v22.2b14-DSv10/Win32/
skylib_mudos_v1/v22.2b14-DSv10/compat/
skylib_mudos_v1/v22.2b14-DSv10/compat/simuls/
skylib_mudos_v1/v22.2b14-DSv10/include/
skylib_mudos_v1/v22.2b14-DSv10/mudlib/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/clone/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/command/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/data/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/etc/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/include/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/inherit/master/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/log/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/compiler/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/efuns/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/single/tests/operators/
skylib_mudos_v1/v22.2b14-DSv10/testsuite/u/
skylib_mudos_v1/v22.2b14-DSv10/tmp/
skylib_mudos_v1/v22.2b14-DSv10/windows/
/**
 * These are some simul efuns converted to efuns.
 * @author Reio Remma aka Sandoz, 2002.
 */

#ifdef LATTICE
#include "/lpc_incl.h"
#include "/file.h"
#include "/simul_efun.h"
#include "/sprintf.h"
#include "/port.h"
#else
#include "../lpc_incl.h"
#include "../file.h"
#include "../simul_efun.h"
#include "../sprintf.h"
#include "../port.h"
#include "../efun_protos.h"
#endif

#ifdef F_REAL_TIME
void f_real_time PROT((void)) {
    push_number(time(NULL));
} /* f_real_time() */
#endif

#ifdef F_VOWEL
static int vowel P1( int, i ) {
    switch( i ) {
      case 'a':
      case 'e':
      case 'i':
      case 'o':
      case 'u':
      case 'A':
      case 'E':
      case 'I':
      case 'O':
      case 'U':
        return 1;
      default:
        return 0;
    }
} /* vowel() */

void f_vowel PROT((void)) {
    sp->u.number = vowel(sp->u.number);
} /* f_vowel() */
#endif

#ifdef F_ADD_A
void f_add_a PROT((void)) {
    char *ret;
    int i = 0, len, sz = SVALUE_STRLEN(sp);

    while( sp->u.string[i] == ' ')
        i++;

    len = sz - i;

    if( vowel( sp->u.string[ i ] ) ) {
        ret = new_string( len + 3, "f_add_a: ret");
        ret[len+3] = 0;
        strcpy( ret, "an ");
        if( len )
            strncpy( ret + 3, sp->u.string + i, len );
    } else {
        ret = new_string( len + 2, "f_add_a: ret");
        ret[len+2] = 0;
        strcpy( ret, "a ");
        if( len )
            strncpy( ret + 2, sp->u.string + i, len );
    }

    free_string_svalue(sp);
    put_malloced_string(ret);

} /* f_add_a() */
#endif

#ifdef F_BASE_NAME
void f_base_name PROT((void)) {
    char *name, *tmp;
    int i;

    if( sp->type == T_OBJECT ) {
        if( sp->u.ob->flags & O_DESTRUCTED ) {
            free_object( sp->u.ob, "f_base_name");
            *sp = const0u;
            return;
        }
        name = (char *)add_slash(sp->u.ob->name);
        free_object( sp->u.ob, "f_base_name");
    } else {
        name = string_copy( sp->u.string, "f_base_name: name");
        free_string_svalue(sp);
    }

    if( ( tmp = strchr( name, '#') ) != NULL ) {
        char *ret;
        i = tmp - name;
        ret = new_string( i, "f_base_name: ret");
        ret[i] = 0;
        strncpy( ret, name, i );
        FREE_MSTR(name);
        put_malloced_string(ret);
    } else {
        put_malloced_string(name);
    }

} /* f_base_name() */
#endif

#ifdef F_ORDINAL
static char *ordinal P1( int, number ) {
    int i, num_l, nve, num;
    char *ret;

    if( number < 0 ) {
        number *= -1;
        num = number & 0x7fffffff;
        nve = 1;
    } else {
        num = number;
        nve = 0;
    }

    for( i = num / 10, num_l = nve + 1; i; i /= 10, num_l++ );

    ret = new_string( num_l+2, "ordinal: ret");
    ret[num_l+2] = 0;

    i = num_l;

    while( num_l-- ) {
        ret[num_l] = ( num % 10 ) + '0';
        num /= 10;
    }

    if( nve )
        ret[0] = '-';

    if( ( number % 100 > 10 ) && ( number % 100 < 14 ) ) {
        strcpy( ret + i, "th");
    } else {
        switch( number % 10 ) {
          case 1:
            strcpy( ret + i, "st");
          break;
          case 2:
            strcpy( ret + i, "nd");
          break;
          case 3:
            strcpy( ret + i, "rd");
          break;
          default:
            strcpy( ret + i, "th");
        }
    }

    return ret;

} /* ordinal */

void f_ordinal PROT((void)) {
    char *ret;

    ret = ordinal(sp->u.number);

    if( !ret )
        put_number(0);
    else
        put_malloced_string(ret);

} /* f_ordinal */
#endif

#ifdef F_SHUFFLE
void f_shuffle PROT((void)) {
    if( sp->type == T_ARRAY && sp->u.arr ) {
        array_t *arr = sp->u.arr;

        if( arr->size > 1 ) {
            svalue_t sv;
            int i, j;

            for( i = 0; i < arr->size; i++ ) {
                if( i == ( j = random_number( i + 1 ) ) )
                    continue;

                sv = arr->item[i];
                arr->item[i] = arr->item[j];
                arr->item[j] = sv;
            }
        }
    } else {
        pop_stack();
        push_refed_array(&the_null_array);
    }

} /* f_shuffle() */
#endif

#ifdef F_CHOICE
static void choose_from_array P2( svalue_t *, ret, array_t *, arr ) {
    int i;

    if( !( i = arr->size ) ) {
        assign_svalue_no_free( ret, &const0 );
    } else {
        i = random_number( i );
        if( arr->item[i].type == T_OBJECT &&
		    ( arr->item[i].u.ob->flags & O_DESTRUCTED ) ) {
		    assign_svalue( &arr->item[i], &const0u );
		}
        assign_svalue_no_free( ret, &arr->item[i] );
    }

    free_array(arr);

} /* choose_from_array() */

void f_choice PROT((void)) {
    int i;
    svalue_t ret;

    switch( sp->type ) {
      case T_ARRAY :
        choose_from_array( &ret, sp->u.arr );
        *sp = ret;
      break;
      case T_STRING :
        if( !( i = SVALUE_STRLEN(sp) ) ) {
            assign_svalue( sp, &const0 );
        } else {
            i = sp->u.string[ random_number( i ) ];
            free_string_svalue(sp);
            put_number(i);
        }
      break;
      case T_MAPPING :
        choose_from_array( &ret, mapping_values( sp->u.map ) );
        free_mapping( sp->u.map );
        *sp = ret;
      break;
      default:
        bad_argument( sp, T_ARRAY | T_STRING | T_MAPPING, 1, F_CHOICE );
    }
} /* f_choice() */
#endif

#if defined(F_UNIQ_ARRAY) || defined(F_DISTINCT_ARRAY) || defined(F_FIND_MEMBER)
static int test_member P3( array_t *, arr, svalue_t *, find, int, size ) {
    int flen, ret = 0;
    svalue_t *sv;

    if( find->type == T_STRING ) {
        if( find->subtype & STRING_COUNTED )
            flen = MSTR_SIZE(find->u.string);
        else
            flen = 0;
    }

    while( size-- ) {
        switch( find->type | ( sv = arr->item + size )->type ) {
          case T_STRING:
            if( flen && ( sv->subtype & STRING_COUNTED ) &&
                flen != MSTR_SIZE(sv->u.string) )
                continue;
            if( strcmp( find->u.string, sv->u.string ) )
                continue;
            break;
          case T_NUMBER:
            if( find->u.number == sv->u.number )
                break;
            continue;
          case T_REAL:
            if( find->u.real == sv->u.real )
                break;
            continue;
          case T_ARRAY:
            if( find->u.arr == sv->u.arr )
                break;
            continue;
          case T_OBJECT:
		    if( sv->u.ob->flags & O_DESTRUCTED ) {
		        assign_svalue( sv, &const0u );
		        continue;
		    }
            if( find->u.ob == sv->u.ob )
                break;
            continue;
          case T_MAPPING:
            if( find->u.map == sv->u.map )
                break;
            continue;
          case T_FUNCTION:
            if( find->u.fp == sv->u.fp )
                break;
            continue;
#ifndef NO_BUFFER_TYPE
          case T_BUFFER:
            if( find->u.buf == sv->u.buf )
                break;
            continue;
#endif
          default:
            if( sv->type == T_OBJECT && (sv->u.ob->flags & O_DESTRUCTED) ) {
                assign_svalue( sv, &const0u );
                if( find->type == T_NUMBER && !find->u.number )
                    break;
		    }
            continue;
	    }
	    ret = 1;
        break;
	}

    return ret;

} /* test_member() */

static void distinct_array P1( svalue_t *, sv ) {
    array_t *tmp, *ret;
    int i, j = 0, size = sv->u.arr->size;

    if( !size )
        return;

    tmp = allocate_empty_array( size );

    for( i = 0; i < size; i++ )
        if( !test_member( tmp, &sv->u.arr->item[i], j ) )
            assign_svalue_no_free( &tmp->item[j++], &sv->u.arr->item[i] );

    while( size-- > j )
        assign_svalue_no_free( &tmp->item[size], &const0u );

    ret = allocate_empty_array( j );

    while( j-- )
        assign_svalue_no_free( &ret->item[j], &tmp->item[j] );

    free_array( sv->u.arr );
    free_array( tmp );
    put_array( ret );

} /* distinct_array() */
#endif

#ifdef F_UNIQ_ARRAY
void f_uniq_array PROT((void)) {
    distinct_array( sp );
} /* f_uniq_array() */
#endif

#ifdef F_DISTINCT_ARRAY
void f_distinct_array PROT((void)) {
    distinct_array( sp );
} /* f_distinct_array() */
#endif

#ifdef F_ROLL_MDN
void f_roll_MdN PROT((void)) {
    int dice, sides, roll = 0;

    sides = sp->u.number;
    pop_stack();
    dice = sp->u.number;

    if( dice > 0 && sides > 0 ) {
        while( dice-- )
            roll += 1 + random_number( sides );
    }

    sp->u.number = roll;

} /* f_roll_MdN() */
#endif

#ifdef F_QUERY_GROUP
static int query_group( object_t *ob ) {
    svalue_t *ret;

    if( ob->flags & O_DESTRUCTED )
        return 0;

    if( !( ret = apply("group_object", ob, 0, ORIGIN_EFUN ) ) ) {
        char *str = "group object";
        copy_and_push_string(str);
        ret = apply("query_property", ob, 1, ORIGIN_EFUN );
    }

    return ( ret && ret->type == T_NUMBER && ret->u.number > 0 );

} /* query_group() */

void f_query_group PROT((void)) {
    int ret = 0;

    if( sp->type == T_OBJECT ) {
        ret = query_group( sp->u.ob );
        free_object( sp->u.ob, "f_query_group");
    } else {
        if( ( ret = sp->u.arr->size ) > 0 ) {
            if( ret == 1 ) {
                if( sp->u.arr->item[0].type == T_OBJECT )
                    ret = query_group( sp->u.arr->item[0].u.ob );
                else
                    ret = 0;
            } else {
                ret = 1;
            }
        }
        free_array( sp->u.arr );
    }

    put_number( ret );

} /* f_query_group() */
#endif

#ifdef F_FILE_EXISTS
void f_file_exists PROT((void)) {
    int i = file_size(sp->u.string);
    free_string_svalue(sp);
    put_number( i > -1 );
} /* f_file_exists() */
#endif

#ifdef F_DIR_EXISTS
void f_dir_exists PROT((void)) {
    int i = file_size(sp->u.string);
    free_string_svalue(sp);
    put_number( i == -2 );
} /* f_dir_exists() */
#endif

#ifdef F_DELETE
void f_delete PROT((void)) {
    int i, start = (sp-1)->u.number, len = sp->u.number, size;

    pop_n_elems( 2 );

    if( start < 0 )
        error("Bad argument 2 to delete() (negative starting index).\n");

    if( len < 1 )
        error("Bad argument 3 to delete() (invalid length).\n");

    if( sp->type == T_ARRAY ) {
        array_t *ret;

        if( !( size = sp->u.arr->size ) )
            return;

        if( start > size - 1 )
            error("Bad argument 2 to delete() (index out of bounds).\n");

        if( start + len > size )
            len = size - start;

        size -= len;
        ret = allocate_empty_array( size );

        for( i = 0; i < start; i++ )
            assign_svalue_no_free( &ret->item[i], &sp->u.arr->item[i] );

        for( ; i < size; i++ )
            assign_svalue_no_free( &ret->item[i], &sp->u.arr->item[i+len] );

        free_array( sp->u.arr );
        put_array( ret );

    } else {
        char *ret;

        if( !( size = SVALUE_STRLEN(sp) ) )
            return;

        if( start > size - 1 )
            error("Bad argument 2 to delete() (index out of bounds).\n");

        if( start + len > size )
            len = size - start;

        size -= len;
        ret = new_string( size, "delete: ret");
        ret[size] = 0;

        if( start )
            strncpy( ret, sp->u.string, start );

        strncpy( ret + start, sp->u.string + start + len, size - start );

        free_string_svalue(sp);
        put_malloced_string(ret);

    }

} /* delete() */
#endif

#ifdef F_INSERT
void f_insert PROT((void)) {
    svalue_t *sv;
    int pos, size, i;

    if( ( pos = sp->u.number ) < 0 )
        pos = 0;

    pop_stack();
    sv = sp - 1;

    if( sv->type == T_ARRAY ) {
        array_t *ret;

        if( pos > ( size = sv->u.arr->size ) )
            pos = size;

        ret = allocate_empty_array( ++size );

        for( i = 0; i < pos; i++ )
            assign_svalue_no_free( &ret->item[i], &sv->u.arr->item[i] );

        assign_svalue_no_free( &ret->item[i++], sp );

        for( ; i < size; i++ )
            assign_svalue_no_free( &ret->item[i], &sv->u.arr->item[i-1] );

        pop_stack();
        free_array( sp->u.arr );
        put_array(ret);

    } else if( sv->type == T_STRING ) {
        char *ret;

        CHECK_TYPES( sp, T_STRING, 2, F_INSERT );

        if( pos > ( size = SVALUE_STRLEN(sv) ) )
            pos = size;

        if( !( i = SVALUE_STRLEN(sp) ) ) {
            ret = string_copy( sp->u.string, "insert: ret");
        } else {
            ret = new_string( size + i, "insert: ret");
            ret[size+i] = 0;

            if( pos > 0 )
                strncpy( ret, sv->u.string, pos );

            strncpy( ret + pos, sp->u.string, i );

            if( size -= pos )
                strncpy( ret + pos + i, sv->u.string + pos, size );
        }

        free_string_svalue(sp--);
        free_string_svalue(sp);
        put_malloced_string(ret);

    } else {
        bad_argument( sv, T_STRING | T_ARRAY, 1, F_INSERT );
    }

} /* f_insert() */
#endif

#ifdef F_INDENT
void f_indent PROT((void)) {
    int cols, indent;
    char *str;

    cols = sp->u.number;
    indent = (sp-1)->u.number;
    str = string_copy( (sp-2)->u.string, "f_indent: str");
    pop_n_elems(3);

    push_number( indent );
    copy_and_push_string("");
    push_number( cols - indent - 1 );
    push_malloced_string( str );
    str = (char *)string_print_formatted("%*=s%-=*s", 4, sp - 3 );
    pop_n_elems(4);

    push_malloced_string(str);

} /* indent() */
#endif

#ifdef F_QUERY_SHADOWS
void f_query_shadows PROT((void)) {
    object_t *obj, *tmp;
    int i = 0;

    tmp = obj = sp->u.ob;

    while( ( tmp = obj->shadowed ) ) {
        obj = tmp;
        i++;
    }

    if( i ) {
        array_t *arr;

        arr = allocate_empty_array( i );

        i = 0;

        tmp = obj = sp->u.ob;

        while( ( tmp = obj->shadowed ) ) {
            arr->item[i].type = T_OBJECT;
            arr->item[i].u.ob = tmp;
            add_ref( arr->item[i].u.ob, "f_query_shadows");
            obj = tmp;
            i++;
        }

        free_object( sp->u.ob, "f_query_shadows");
        put_array( arr );
    } else {
        free_object( sp->u.ob, "f_query_shadows");
        put_number(0);
    }

} /* f_query_shadows() */
#endif

#ifdef F_QUERY_MULTIPLE_SHORT
static void qms_type_error PROT((void)) {
    error("Bad argument 2 to query_multiple_short() - must be one of "
        "\"a\", \"the\", \"one\", \"poss\" or zero.\n");
} /* qms_type_error() */

#define QMS_FREE FREE(lens); \
                 free_array(arr);

void f_query_multiple_short PROT((void)) {
    svalue_t *val, *sv;
    array_t *obs, *arr;
    char *type = NULL, *ret, *tmp;
    int no_dollars = 0, flag = 0, j = 0, total = 0, i, sz, real;
    int *lens;

    switch( st_num_arg ) {
      case 4:
        flag = sp->u.number;
        pop_stack();
      case 3:
        no_dollars = sp->u.number;
        pop_stack();
      case 2:
        switch( sp->type ) {
          case T_STRING:
            if( !( i = SVALUE_STRLEN(sp) ) )
                qms_type_error();

            type = new_string( i + 6, "f_query_multiple_short: type");
            type[i+6] = 0;
            strncpy( type, sp->u.string, i );
            strncpy( type + i, "_short", 6 );

          break;
          case T_NUMBER:
            if( !sp->u.number )
                break;
          default:
            qms_type_error();
        }

        pop_stack();

      case 1:
        if( !( sz = ( obs = sp->u.arr )->size ) ) {
            if( type )
                FREE_MSTR(type);
            free_empty_array( sp->u.arr );
            put_constant_string("");
            return;
        }

        if( !type )
            type = string_copy("a_short", "f_query_multiple_short: type");

        arr = allocate_empty_array( sz );
        lens = CALLOCATE( sz, int, TAG_TEMPORARY, "f_query_multiple_short: lens");

        for( i = 0, real = 0; i < sz; i++ ) {
            svalue_t *retval;

            sv = &obs->item[i];

        	if( sv->type == T_OBJECT ) {
        	    if( sv->u.ob->flags & O_DESTRUCTED ) {
        	        assign_svalue( sv, &const0u );
        	    } else {
                    push_number(flag);
                    if( ( retval = apply( type, sv->u.ob, 1, ORIGIN_EFUN ) ) &&
                        ( retval->type == T_STRING ) ) {
                        val = &arr->item[real];
                        assign_svalue_no_free( val, retval );
                        total += ( lens[real++] = SVALUE_STRLEN( val ) );
                    }
        	    }
        	} else {
        	    j = 1;
        	    if( sv->type == T_STRING ) {
                    val = &arr->item[real];
        	        assign_svalue_no_free( val, sv );
                    total += ( lens[real++] = SVALUE_STRLEN( val ) );
        	    }
        	}
        }

        for( i = real; i < sz; i++ )
            assign_svalue_no_free( &arr->item[i], &const0u );

        FREE_MSTR(type);
        free_array( sp->u.arr );

        if( !( sz = real ) ) {
            QMS_FREE;
            put_constant_string("");
            return;
        }
    }

    /* Only objects and no conversion. */
    if( !j && !no_dollars ) {
        total += 6;

        if( total > MAX_STRING_LENGTH ) {
            QMS_FREE;
            error("Maximum string length exceeded in "
                "query_multiple_short().\n");
        }

        tmp = ( ret = new_string( total, "f_query_multiple_short: tmp") );
        ret[total] = 0;

        strncpy( tmp, "$M$", 3 );
        tmp += 3;

        for( i = 0; i < sz; i++ ) {
            sv = &arr->item[i];
            strncpy( tmp, sv->u.string, lens[i] );
            tmp += lens[i];
        }

        strncpy( tmp, "$M$", 3 );

        goto end_qms;

    }

    switch( sz ) {
      case 1:
        ret = string_copy( arr->item[0].u.string, "f_query_multiple_short: ret");
      break;
      case 2:
        total += 5;

        if( total > MAX_STRING_LENGTH ) {
            QMS_FREE;
            error("Maximum string length exceeded in "
                "query_multiple_short().\n");
        }

        tmp = ( ret = new_string( total, "f_query_multiple_short: ret") );
        ret[total] = 0;

        strncpy( tmp, arr->item[0].u.string, lens[0] );
        strncpy( tmp += lens[0], " and ", 5 );
        strncpy( tmp += 5, arr->item[1].u.string, lens[1] );

      break;
      default:
        total += ( sz - 2 ) * 2 + 5;

        if( total > MAX_STRING_LENGTH ) {
            QMS_FREE;
            error("Maximum string length exceeded in "
                "query_multiple_short().\n");
        }

        tmp = ( ret = new_string( total, "f_query_multiple_short: ret") );
        ret[total] = 0;

        total = sz - 2;

        for( i = 0; i < total; i++ ) {
            sv = &arr->item[i];
            strncpy( tmp, sv->u.string, lens[i] );
            strncpy( tmp += lens[i], ", ", 2 );
            tmp += 2;
        }

        sv = &arr->item[i];
        strncpy( tmp, sv->u.string, lens[i] );
        strncpy( tmp += lens[i], " and ", 5 );
        sv = &arr->item[++i];
        strncpy( tmp += 5, sv->u.string, lens[i] );
    }

    if( no_dollars ) {
        object_t *ob;

        if( ( ob = command_giver ) || ( ob = find_object("/global/player") ) ) {
            push_malloced_string(ret);
            if( ( val = apply("convert_message", ob, 1, ORIGIN_EFUN ) ) &&
                ( val->type == T_STRING ) ) {
                QMS_FREE;
                assign_svalue_no_free( sp, val );
                return;
            }
        } else {
            FREE_MSTR(ret);
        }

        QMS_FREE;
        put_constant_string("");
        return;

    }

    end_qms:
    QMS_FREE;
    put_malloced_string(ret);

} /* f_query_multiple_short() */
#endif

#ifdef F_REFERENCE_ALLOWED

int in_reference_allowed = 0;

void f_reference_allowed PROT((void)) {
    int invis, len, ret = 0, sz;
    svalue_t *sv;
    object_t *ob;
    char *referrer;

    if( in_reference_allowed ) {
        pop_2_elems();
        push_number(1);
        return;
    }

    if( ( ob = (sp-1)->u.ob )->flags & O_DESTRUCTED ) {
	    free_object( ob, "f_reference_allowed");
	    *(sp-1) = const0u;
	    pop_2_elems();
	    push_number(0);
	    return;
    }

    if( !( sv = apply("query_invis", ob, 0, ORIGIN_EFUN ) ) ||
        ( sv->type == T_NUMBER && !( invis = sv->u.number ) ) ) {
        pop_2_elems();
        push_number(1);
        return;
    }

    switch( sp->type ) {
      case T_OBJECT:
        if( sp->u.ob == ob ) {
            pop_2_elems();
            push_number(1);
            return;
        }
        if( !( sv = apply("query_name", sp->u.ob, 0, ORIGIN_EFUN ) ) ||
            sv->type != T_STRING ) {
            pop_2_elems();
            push_number(0);
            return;
        }
      break;
      case T_STRING:
        sv = sp;
      break;
      case T_NUMBER:
        if( sp->u.number )
            bad_argument( sp, T_OBJECT | T_STRING, 2, F_REFERENCE_ALLOWED );
        pop_2_elems();
        push_number(0);
        return;
      default:
        bad_argument( sp, T_OBJECT | T_STRING, 2, F_REFERENCE_ALLOWED );
    }

    if( !( len = SVALUE_STRLEN(sv) ) ) {
        pop_2_elems();
        push_number(0);
        return;
    }

    referrer = new_string( len, "f_reference_allowed: referrer");
    referrer[len] = 0;
    strncpy( referrer, sv->u.string, len );

    in_reference_allowed = 1;

    if( ( sv = apply("query_allowed", ob, 0, ORIGIN_EFUN ) ) &&
        sv->type == T_ARRAY && ( sz = sv->u.arr->size ) ) {
        int i, pt = 0, fr = 0;
        array_t *arr = sv->u.arr;

        while( sz-- ) {
            sv = arr->item + sz;
            if( sv->type == T_STRING && ( i = SVALUE_STRLEN(sv) ) ) {
                if( i == len && ( ret = !strcmp( sv->u.string, referrer ) ) ) {
                    goto end_ref_allowed;
                } else {
                    if( !fr && i == 7 )
                        fr = !strcmp( sv->u.string, "friends");
                    if( !pt && i == 11 )
                        pt = !strcmp( sv->u.string, "playtesters");
                }
            }
        }

        if( fr ) {
            copy_and_push_string( referrer );
            if( ( sv = apply("query_friend", ob, 1, ORIGIN_EFUN ) ) &&
                sv->type == T_NUMBER && ( ret = ( sv->u.number > 0 ) ) ) {
                goto end_ref_allowed;
            }
        }

        if( pt && simul_efun_ob ) {
            copy_and_push_string( referrer );
            if( ( sv = apply("playtesterp", simul_efun_ob, 1, ORIGIN_EFUN ) ) &&
                sv->type == T_NUMBER && ( ret = ( sv->u.number > 0 ) ) ) {
                goto end_ref_allowed;
            }
        }

    }

    if( simul_efun_ob ) {
        switch( invis ) {
          case 3 :
            copy_and_push_string( referrer );
            ret = ( ( sv = apply("adminp", simul_efun_ob, 1, ORIGIN_EFUN ) ) &&
                      sv->type == T_NUMBER && sv->u.number > 0 );
          break;
          case 2 :
            copy_and_push_string( referrer );
            ret = ( ( sv = apply("lordp", simul_efun_ob, 1, ORIGIN_EFUN ) ) &&
                      sv->type == T_NUMBER && sv->u.number > 0 );
          break;
          case 1 :
            copy_and_push_string( referrer );
            ret = ( ( sv = apply("creatorp", simul_efun_ob, 1, ORIGIN_EFUN ) ) &&
                      sv->type == T_NUMBER && sv->u.number > 0 );
          break;
          default :
            ret = 1;
        }
    }

    end_ref_allowed:
    in_reference_allowed = 0;
    FREE_MSTR(referrer);
    pop_2_elems();
    push_number(ret);

} /* f_reference_allowed() */
#endif

#ifdef F_FIND_MEMBER
void f_find_member PROT((void)) {
    int i = 0, sz = 0, len, *arr;
    svalue_t *sv;
    array_t *ret;

    switch( sp->type ) {
      case T_STRING : {
          char *tmp;
          int what;

          CHECK_TYPES( sp-1, T_NUMBER, 1, F_FIND_MEMBER );

          if( !( len = SVALUE_STRLEN(sp) ) ) {
              free_string_svalue(sp--);
              put_array( &the_null_array );
              return;
          }

          arr = CALLOCATE( len, int, TAG_TEMPORARY, "f_find_member: arr");
          what = (sp-1)->u.number;

          while( ( tmp = strchr( sp->u.string + i, what ) ) ) {
              i = tmp - sp->u.string;
              arr[sz++] = i++;
          }

          free_string_svalue(sp--);

      }
      break;
      case T_ARRAY : {
          svalue_t *what;
          int slen = 0;

          if( !( len = sp->u.arr->size ) ) {
              pop_2_elems();
              push_array( &the_null_array );
              return;
          }

          arr = CALLOCATE( len, int, TAG_TEMPORARY, "f_find_member: arr");
          what = sp-1;

          if( what->type == T_STRING && ( what->subtype & STRING_COUNTED ) )
              slen = MSTR_SIZE( what->u.string );

          for( i = 0; i < len; i++ ) {
              switch( what->type | ( sv = sp->u.arr->item + i )->type ) {
                case T_STRING:
                  if( slen && ( sv->subtype & STRING_COUNTED ) &&
                      slen != MSTR_SIZE( sv->u.string ) )
                      continue;
                  if( strcmp( what->u.string, sv->u.string ) )
                      continue;
                  break;
                case T_NUMBER:
                  if( what->u.number == sv->u.number )
                      break;
                  continue;
                case T_REAL:
                  if( what->u.real == sv->u.real )
                      break;
                  continue;
                case T_ARRAY:
                  if( what->u.arr == sv->u.arr )
                      break;
                  continue;
                case T_OBJECT:
                  if( sv->u.ob->flags & O_DESTRUCTED ) {
                      assign_svalue( sv, &const0u );
                      continue;
                  }
                  if( what->u.ob == sv->u.ob )
                      break;
                  continue;
                case T_MAPPING:
                  if( what->u.map == sv->u.map )
                      break;
                  continue;
                case T_FUNCTION:
                  if( what->u.fp == sv->u.fp )
                      break;
                  continue;
#ifndef NO_BUFFER_TYPE
                case T_BUFFER:
                  if( what->u.buf == sv->u.buf )
                      break;
                  continue;
#endif
                default:
                  if( sv->type == T_OBJECT &&
                      ( sv->u.ob->flags & O_DESTRUCTED ) ) {
                      assign_svalue( sv, &const0u );
                      if( what->type == T_NUMBER && !what->u.number )
                          break;
      		      }
                  continue;
      	      }
      	      arr[sz++] = i;
          }
          free_array( (sp--)->u.arr );
      }
      break;
      default:
        bad_argument( sp, T_STRING | T_ARRAY, 2, F_FIND_MEMBER );
    }

    ret = allocate_empty_array( sz );

    while( sz-- ) {
        sv = ret->item + sz;
        sv->type = T_NUMBER;
        sv->u.number = arr[sz];
    }

    pop_stack();
    FREE(arr);
    push_refed_array(ret);

} /* f_find_member() */
#endif

#ifdef F_EVENT
/* EVENTS!
 * Okay. This is pretty simple.
 * Calls the function "event_"+event_name in the object specified.
 * If the object is an array, calls it in each.
 * If the object is a room, call it on its inventory.
 *  [Incorrect: actually calls it on all_inventory() of any object but
 *   only if addressed uniquely]
 * Passes all the parameters too.
 * ---
 * From FluffOS.
 * Made it a wee little faster and changed to clean up destructed objects.
 * - Sandoz.
 */
static void event P4( svalue_t *, event_ob, svalue_t *, event_fun, int, numparam,
                      svalue_t *, event_param ) {
    int i = SVALUE_STRLEN(event_fun);
    object_t *ob, *origin;
    svalue_t *sv;
    char *name;

    origin = current_object;

    name = new_string( i + 6, "newmoon.c: au_event");
    name[i+6] = 0;
    strncpy( name, "event_", 6 );
    strncpy( name + 6, event_fun->u.string, i );

    switch( event_ob->type ) {
      case T_ARRAY :
        for( i = 0; i < event_ob->u.arr->size; i++ ) {
            sv = event_ob->u.arr->item + i;
            if( sv->type == T_OBJECT ) {
                if( !( sv->u.ob->flags & O_DESTRUCTED ) ) {
                    push_object(origin);
                    push_some_svalues( event_param, numparam );
                    apply( name, sv->u.ob, numparam + 1, ORIGIN_EFUN );
                } else {
                    free_object( sv->u.ob, "event");
    	            *sv = const0u;
                }
            }
        }
      break;
      case T_OBJECT :
        if( !( event_ob->u.ob->flags & O_DESTRUCTED ) ) {
            /* First we call the event on the object itself */
            push_object(origin);
            push_some_svalues( event_param, numparam );
            apply( name, event_ob->u.ob, numparam + 1, ORIGIN_EFUN );

            /* And then call it on it's inventory... */
            for( ob = event_ob->u.ob->contains; ob; ob = ob->next_inv ) {
                if( ob != origin && !( ob->flags & O_DESTRUCTED ) ) {
                    push_object(origin);
                    push_some_svalues( event_param, numparam );
                    apply( name, ob, numparam + 1, ORIGIN_EFUN );
                }
            }
        } else {
            free_object( event_ob->u.ob, "event");
            *event_ob = const0u;
        }
      break;
      default:
        FREE_MSTR(name);
        bad_argument( event_ob, T_OBJECT | T_ARRAY, 1, F_EVENT );
    }

    FREE_MSTR(name);

} /* event() */

void f_event PROT ((void)) {
    int num = st_num_arg;
    svalue_t *start = sp - num;

    event( start + 1, start + 2, num - 2, start + 3 );

    pop_n_elems(num);

} /* f_event() */
#endif

#ifdef F_QUERY_PRIME
void f_query_prime PROT((void)) {
    int num = sp->u.number, div = 2;

    for( ; div <= num / 2; div++ )
        if( !( num % div ) ) {
            put_number( 0 );
            return;
        }

    put_number( 1 );

} /* f_query_prime() */
#endif

#ifdef F_MUD_NAME
void f_mud_name PROT((void)) {
#ifdef MUD_NAME
    copy_and_push_string(MUD_NAME);
#else
    copy_and_push_string("Broken Mud Name");
#endif
} /* f_mud_name() */
#endif