/* -*- LPC -*- */
/*
* $Locker: $
* $Id: item_chat.c,v 1.9 2002/04/19 20:51:06 aquilo Exp $
* $Log: item_chat.c,v $
* Revision 1.9 2002/04/19 20:51:06 aquilo
* Added call to check_chat() in item_chat(), as per Sousjagne's suggestion.
*
* Revision 1.8 2001/11/05 21:03:50 pinkfish
* Fix up a weird error with interactive and environments.
*
* Revision 1.7 2001/08/20 16:23:54 aquilo
* Fixed up saving & restoring of chats
*
* Revision 1.6 2001/08/18 14:43:11 aquilo
* Made the changes work this time. (didn't take into account environment() == 0 first
* time)
*
* Revision 1.3 2000/03/28 21:23:46 ceres
* Can't remember
*
* Revision 1.2 1999/09/14 05:08:27 shaggy
* Made documentation more complete
*
* Revision 1.1 1998/01/06 03:59:10 ceres
* Initial revision
*
*/
/** -*- LPC -*-
* This class handles atmospheric chat messages.
*/
#include <room.h>
private nosave int _off, _already_added;
private nosave mixed *_chats;
void check_chat();
/**
* @return The raw data telling us what to chat and when
*/
mixed *query_chats() { return _chats; }
/** @ignore yes */
void init() {
check_chat();
} /* init() */
/**
* This method adds atmospheric chat messages to the object.
* The array which is passed into the object has three
* elements, the first element is the minimum time between chats, the second
* parameter is the maximum time bewteen chats and the third parameter
* is the list of actual chats.
* <p>
* Item chats are strings which are printed at (semi) random
* intervals to living objects holding or in the same room as
* someone holding the object. Currently they will not be
* heard outside containers. They are used to add
* atmosphere to an Item. A chat will be picked at random
* from the array of chats with a frequency controlled by the
* times min and max. ie. one will be picked every n seconds
* where is varies between min and max seconds. Please
* don't make the values for min and max too small or the
* messages just become annoying!
* <p>
* Currently, there's a maximum on the min/max values, every
* value higher than 320 seconds is treated as that.
* <p>
* The chats can contain one of $a_short$, $the_short$ and
* $poss_short$ which will be replaced with the
* corresponding value.
* <p>
* To call a function defined on the item in place of a chat message
* use "#function_name" in place of a chat string.
* <p>
* To use item chats, the object needs to inherit
* "/std/basic/item_chat" and if the object defines an init()
* function, that function should also call ::init()
* <p>
* To make the chatting object save the values, it's necessary
* to define a couple of supporting functions in the item:
* <pre>
* mapping query_dynamic_auto_load() {
* mapping tmp;
*
* tmp = ([ "::" : object::query_dynamic_auto_load(),
* "chat" : item_chat::query_dynamic_auto_load(), ]);
* return tmp;
* } \/\* query_dynamic_auto_load() *\/
*
* void init_dynamic_arg(mapping map) {
* if (map["::"])
* object::init_dynamic_arg(map["::"]);
* if (map["chat"])
* item_chat::init_dynamic_arg(map["chat"]);
* } /\* init_dynamic_arg() *\/
*
* </pre>
* Use object in the previous if the object is inheriting /std/object, if not,
* then use whatever it's inheriting from instead.
* @example item_chat( ({ 120, 240,
* ({ "A revolting smell drifts from $the_short$.",
* "Something rustles in $the_short$." }) }) );
*/
void item_chat( mixed *args ) {
if ( !args || sizeof(args) < 3 || !sizeof(args[2]) ){
write( "Incorrect args to item_chat.\n" );
return;
}
/* We save original version, not replaced one, as the a_short stuff will point
to wrong obs when we next load */
// _saved_version = args;
args = args - ({ 0 });
args[2] = map( args[2],
(: replace( $1, ({ "$a_short$", this_object()->a_short(),
"$the_short$", this_object()->the_short(),
"$poss_short$", this_object()->poss_short() }) ) :) );
_off = 0;
_chats = args + ({ 0 });
check_chat();
} /* item_chat() */
/**
* This starts the object chatting. This is done automaticly when entering
* the presence of an interactive object
* @see item_chat()
* @see chat_off()
*/
void chat_on(){
_off = 0;
check_chat();
} /* chat_on() */
/**
* This stops the object chatting. This is done automaticly when leaving
* the prescence of all interactive objects.
* @see chat_on()
* @see item_chat()
*/
void chat_off(){
_off = 1;
} /* chat_off() */
/**
* This method does the actual chat, it prints a message
* and figures that stuff out.
* @see item_chat()
* @see chat_on()
* @see chat_off()
*/
void make_chat(){
int saying;
string stuff;
object env, *targets;
_already_added = 0;
if( !(env = environment()) || _off )
return;
saying = random( sizeof(_chats[ 2 ]) );
if( saying == _chats[ 3 ] )
saying = ( saying + 1 ) % sizeof( _chats[ 2 ] );
_chats[ 3 ] = saying;
stuff = _chats[ 2 ][ saying ];
// Chat if i'm in a room, or in an environment one branch down from an (n)pc
// who is in a room
if( env->query_is_room() ||
( interactive(env) && (env = environment(env)) && env->query_is_room() ) ){
targets = filter( all_inventory(env), (: interactive($1) :) );
if( !sizeof(targets) )
// No one here. Don't chat and don't add ourself to chatter
return;
if( stuff[0..0] == "#" )
call_other( this_object(), stuff[ 1 .. ] );
else
tell_room( env, stuff + "\n" );
// Add ourselves, so we are called again
_already_added = 1;
ROOM_HANDLER->add_chatter( this_object(), _chats[ 0 ] +
random( _chats[ 1 ] - _chats[ 0 ] + 1 ) );
}
} /* make_chat() */
/**
* This method makes sure that we are chatting if we should be.
* @see chat_on()
* @see item_chat()
* @see make_chat()
*/
void check_chat(){
if( !_off && !_already_added && arrayp(_chats) && environment() ){
if( interactive(environment()) ||
( environment(environment()) &&
interactive(environment(environment()))
)
){
_already_added = 1;
ROOM_HANDLER->add_chatter( this_object(),
( _chats[ 0 ] + random( _chats[ 1 ] - _chats[ 0 ] + 1 ) ) / 2 );
}
}
} /* check_chat() */
/** @ignore yes */
mapping query_dynamic_auto_load() {
return ([ "_off" : _off,
"_chats" : _chats
]);
} /* query_dynamic_auto_load() */
/** Fixes saved chats
*/
string fix_saved_chat( string chat ){
string old_ob;
if( !chat )
return 0;
sscanf( chat, "%*s$%*s_short:%s$%*s", old_ob );
if( old_ob )
chat = replace( chat, old_ob, file_name(this_object()) );
return chat;
}
/** @ignore yes */
void init_dynamic_arg( mapping map ) {
mixed info;
if( !map )
return;
if( (info = map["_chats"]) && arrayp(info) && sizeof(info) > 2 ){
info[2] = map( info[2], "fix_saved_chat", this_object() );
item_chat( info );
}
if( !(_off = map["_off"]) )
chat_on();
else
chat_off();
} /* init_dynamic_arg() */