/**
 * The standard chatter inheritable for room chats.
 * @author Pinkfish
 * @changed Added day/night chat code - Sandoz, 2001.
 * @changed Added support for interactive chat parsing - Sandoz, 2002.
 * @changed Removed clean_up() so that our recycled chatters wouldn't
 * be cleaned up by the driver, because the garbage handler will get
 * unreferenced chatters anyway - Sandoz, 2nd Oct. 2002.
 * @see /std/room/basic_room.c
 * @see room_chat
 */
nosave int _off;
nosave object _room;
nosave mixed _chats, _night_chats;
/**
 * Allows the chat interval to be changed.
 * @param min minimum interval between chats (seconds)
 * @param max maximum interval between chats (seconds)
 */
void set_chat_min_max( int min, int  max ) {
    if( _chats ) {
        _chats[0] = min;
        _chats[1] = max;
    }
} /* set_chat_min_max() */
/**
 * Allows the night chat interval to be changed.
 * @param min minimum interval between chats (seconds)
 * @param max maximum interval between chats (seconds)
 */
void set_night_chat_min_max( int min, int  max ) {
    if( _night_chats ) {
        _night_chats[0] = min;
        _night_chats[1] = max;
    }
} /* set_chat_min_max() */
/**
 * Gives the chatter a room to chat at and the chat args.
 * @param my_room room object
 * @param chat_args chat data: ({ min, max, chats array })
 * @see room_chat
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void setup_chatter( object my_room,  mixed chat_args ) {
    _off = 1;
    _room = my_room;
    _chats = chat_args + ({ 0 });
} /* setup_chatter() */
/**
 * Gives the chatter a room to chat at and the chat args
 * for the night chats.
 * @param my_room room object
 * @param chat_args chat data: ({ min, max, chats array })
 * @see room_chat
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void setup_night_chatter( object my_room,  mixed chat_args ) {
    _off = 1;
    _room = my_room;
    _night_chats = chat_args + ({ 0 });
} /* setup_chatter() */
/** @ignore yes */
void dest_me() { destruct(TO); }
/** @ignore yes */
string expand_vis( string str, int visible ) {
    string pre, bright, dark, post;
    while( sscanf( str, "%s$%s|%s$%s", pre, bright, dark, post ) == 4 )
           str = pre + ( visible ? bright : dark ) + post;
    return replace_string( str, "%%", "$")+"\n";
} /* expand_vis() */
/** @ignore yes */
string expand_i( string str, object ob ) {
    string fname;
    fname = file_name(ob);
    return replace( str, ({
               "%Iposs", "$poss_short:"+fname+"$",
               "%Ip", ob->HIS,
               "%Io", ob->HIM,
               "%Ir", ob->HE,
               "%I", "$the_short:"+fname+"$",
               }) );
} /* expand_i() */
/** @ignore yes */
void print_chat( string chat, object *vis ) {
    object *dark, ob;
    string tmp;
    ob = choice(vis);
    vis -= ({ ob });
    tmp = expand_vis( chat, !ob->check_dark( _room->query_light() ) );
    tmp = replace( tmp, ({
        "%Iposs", "your",
        "%Ip", "your",
        "%Io", "you",
        "%Ir", "you",
        "%I", "you",
        }) );
    tell_object( ob, tmp );
    if( !sizeof(vis) )
        return;
    dark = filter( vis, (: $1->check_dark( _room->query_light() ) :) );
    vis -= dark;
    if( sizeof(vis) ) {
        tmp = expand_vis( chat, 1 );
        map( vis, (: tell_object( $1, $2 ) :), expand_i( tmp, ob ) );
    }
    if( sizeof(dark) ) {
        tmp = expand_vis( chat, 0 );
        map( dark, (: tell_object( $1, $2 ) :), expand_i( tmp, ob ) );
    }
} /* print_chat() */
/** @ignore yes */
void make_chat() {
    int saying;
    mixed stuff;
    object *obs;
    if( !sizeof( obs = filter( INV( _room ), (: interactive($1) :) ) ) ) {
        _off = 1;
        return;
    }
    if( !WEATHER_H->query_day() && _night_chats && sizeof(_night_chats[2]) ) {
        saying = random( sizeof( _night_chats[ 2 ] ) );
        if( saying == _night_chats[ 3 ] )
            saying = ( saying + 1 ) % sizeof( _night_chats[ 2 ] );
        _night_chats[ 3 ] = saying;
        stuff = _night_chats[ 2 ][ saying ];
        saying = _night_chats[ 0 ] + random( _night_chats[ 1 ] -
                 _night_chats[ 0 ] + 1 );
    } else if( !_chats || !sizeof(_chats[2]) ) {
        _off = 1;
        return;
    } else {
        saying = random( sizeof( _chats[ 2 ] ) );
        if( saying == _chats[ 3 ] )
            saying = ( saying + 1 ) % sizeof( _chats[ 2 ] );
        _chats[ 3 ] = saying;
        stuff = _chats[ 2 ][ saying ];
        saying = _chats[ 0 ] + random( _chats[ 1 ] - _chats[ 0 ] + 1 );
    }
    if( stringp(stuff) ) {
        if( stuff[ 0 ] == '#' )
            call_other( _room, stuff[1..] );
        else if( stuff[ 0 ] == '@' ) {
            print_chat( (string)call_other( _room, stuff[1..] ), obs );
        } else {
            print_chat( stuff, obs );
        }
    }
    if( functionp( stuff ) )
        print_chat( evaluate( stuff ), obs );
    if( intp( stuff ) )
        map( filter( INV( _room ), (: $1 && living( $1 ) && creatorp($1) :) ),
            (: tell_creator( $1, "Warning: room_chat array contains integer "
            "argument. Did you mix up the syntax with load_chat()'s?\n") :) );
    ROOM_H->add_chatter( TO, saying );
} /* make_chat() */
/**
 * Checks that the chatter is on and being activated
 * properly from the room_handler.
 * @see /std/room/basic/chatter
 * @see /handlers/room_handler
 */
void check_chat() {
    int delay;
    if( !_off || ( !pointerp( _chats ) && !pointerp( _night_chats ) ) )
        return;
    _off = 0;
    delay = ( ( !WEATHER_H->query_day() && _night_chats ) ?
            _night_chats[ 0 ] + random( _night_chats[ 1 ] -
            _night_chats[ 0 ] + 1 ) : ( !pointerp( _chats ) ? 0 :
            _chats[ 0 ] + random( _chats[ 1 ] - _chats[ 0 ] + 1 ) ) ) / 2;
    if( delay )
        ROOM_H->add_chatter( TO, delay );
} /* check_chat() */
/**
 * Adds more chats to the existing set of room chats
 * managed by this chatter object.
 * @param new_chats an array of new chat strings
 * @see remove_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void add_room_chats( string *new_chats ) {
    if( sizeof(new_chats) ) {
        if( sizeof(_chats[2]) )
            _chats[2] = _chats[2] + new_chats;
        else
            _chats[2]= new_chats;
    }
} /* add_room_chats() */
/**
 * Adds more chats to the existing set of room night chats
 * managed by this chatter object.
 * @param new_chats an array of new chat strings
 * @see remove_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void add_room_night_chats( string *new_chats ) {
    if( sizeof(new_chats) ) {
        if( _night_chats && sizeof(_night_chats[2]) )
            _night_chats[2] = _night_chats[2] + new_chats;
        else
            _night_chats[2]= new_chats;
    }
} /* add_room_night_chats() */
/**
 * Removes chats from the set of room chats
 * managed by this chatter object.  If there are no chats
 * left the chatter is recycled or destructed.
 * @param dead_chats an array of chat strings to remove
 * @see add_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void remove_room_chats( string *dead_chats ) {
    if( sizeof(_chats[2]) )
        _chats[2] = _chats[2] - dead_chats;
    if( !sizeof( _chats[2] ) && ( !_night_chats ||
        !sizeof( _night_chats[2] ) ) ) {
        if( _room )
            _room->stop_room_chats(); // Try recycling us.
        if( _room )
            dest_me();
    }
} /* remove_room_chats() */
/**
 * Removes chats from the set of room night chats
 * managed by this chatter object.  If there are no chats
 * left the chatter is destructed.
 * @param dead_chats an array of chat strings to remove
 * @see add_room_chats
 * @see query_room_chats
 * @see /std/room/basic/chatter
 */
void remove_room_night_chats( string *dead_chats ) {
   if( _night_chats && sizeof(_night_chats[2]) )
       _night_chats[2] = _night_chats[2] - dead_chats;
    if( !sizeof( _chats[2] ) && ( !_night_chats ||
        !sizeof( _night_chats[2] ) ) ) {
        if( _room )
            _room->stop_room_chats(); // Try recycling us.
        if( _room )
            dest_me();
    }
} /* remove_room_night_chats() */
/**
 * Returns the the set of room chats
 * managed by this chatter object.
 * @return pointer to the mixed array of chat args
 * @example
 *  ({ 120, 240, ({ "A frog gimbles the curtains.",
 *                  "A truly revolting smell drifts insidiously "
 *                  "from the rug." }) })
 * @see add_room_chats
 * @see remove_room_chats
 * @see room_chat
 * @see /std/room/basic/chatter
 */
mixed query_room_chats() { return _chats; }
/**
 * Returns the the set of room night chats
 * managed by this chatter object.
 * @return pointer to the mixed array of chat args
 * @see query_room_chats()
 * @see remove_room_chats
 * @see room_chat
 * @see /std/room/basic/chatter
 */
mixed query_room_night_chats() { return _night_chats; }
/** @ignore yes */
object query_my_room() { return _room; }