/**************************************************************************/
// saymote.cpp - saymote system written by Kalahn, Idea from Kirion.
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with the dawn license *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
**************************************************************************/
/*
The player types:
saymote >kalahn [with a bow] greetings [and, then, smiling] how have you been?
and Kalahn would see it:
Kirion says to you with a bow: 'greetings' and, then, smiling: 'how have you been?'
Translating the said parts according to the language of the
speaker/listener.
Also supports [[ and ]] to allow a player to actually put '[' and ']' codes
in their says
*/
#include "include.h" // dawn standard includes
/**************************************************************************/
// Kal - June 1999
void saymote( language_data *language, char_data *ch, char *argument, int sayflags)
{
int i;
if(IS_SET(sayflags, SAYFLAG_ONLY_REMEMBERED_CHAR)
&& (!IS_NPC(ch)|| !ch->mprog_target))
{
ch->printlnf("rsay '%s' not processed because you arent remembering anyone.", argument);
return;
}
bool say_with_emotes=true;
if(IS_SET(sayflags, SAYFLAG_NO_SAYMOTE)){
say_with_emotes=false;
}
bool convert_colour=false;
if(IS_SET(sayflags, SAYFLAG_CONVERT_COLOUR)){
convert_colour=true;
}
static int rpmon=0;
const int MAXBUFCOUNT=8;
char tochar_sayask_text[30],
toall_sayask_text[30],
tovictim_sayask_text[30];
char splitbuf[MAXBUFCOUNT][(MIL*2)+3]; // (MIL*2)+3 to prevent $$$$...
// causing buffer overrun
tovictim_sayask_text[0]='\0';
char_data *victim= NULL; // if victim is true we have a sayto target
// clear our buffers
for(i=0; i<MAXBUFCOUNT; i++){
splitbuf[i][0]='\0';
};
// *** idiot checks
if ( IS_NULLSTR(argument) )
{
ch->println("Say what?");
return;
}
// dont allow messages that could be defrauding
if(check_defrauding_argument(ch, argument)){
return;
}
// prevent potential buffer overruns
if (count_char(argument,'$')>10)
{
ch->println("You can't have more than 10 $'s in a saymote.");
return;
}
if (count_char(argument,'[')>10)
{
ch->println("You can't have more than 10 ['s in a say/saymote.");
return;
}
if (count_char(argument,']')>10)
{
ch->println("You can't have more than 10 ]'s in a say/saymote.");
return;
}
if ( !IS_NPC(ch)
&& !IS_SET(language->flags, LANGFLAG_NO_SKILL_REQUIRED)
&& language->gsn>=0
&& get_skill(TRUE_CH(ch), language->gsn)<1 )
{
ch->printlnf("You have no knowledge of any %s words.", language->name);
return;
}
// wiznet RPMONITOR
if (!IS_NPC(ch) && !IS_OOC(ch))
{
rpmon++;
if (rpmon>=20)
{
int rplevel;
char buf2[MSL];
rplevel = (IS_TRUSTED(ch,LEVEL_IMMORTAL)?MAX_LEVEL:get_trust(ch));
sprintf (buf2, "Wiznet rpmonitor: %s says '%s'`x",
ch->name, argument);
wiznet(buf2,ch,NULL,WIZ_RPMONITOR,0,rplevel);
if (rpmon>=23) rpmon=0;
}
}
if(!IS_NPC(ch))
{
ch->pcdata->did_ic=true;
if(is_room_private_to_char(ch->in_room, ch))
{
ch->pcdata->did_ooc=true;
ch->pcdata->did_ic=false;
}
}
// trim off any leading blanks
argument = ltrim_string(argument);
// anti autorps abuse system
if(!IS_NPC(ch) && IS_IC(ch))
{
++ch->pcdata->say_index%=RPS_AUDIT_SIZE;
free_string(ch->pcdata->saycheck[ch->pcdata->say_index]);
ch->pcdata->saycheck[ch->pcdata->say_index]=str_dup(argument);
ch->pcdata->saytimes[ch->pcdata->say_index]=current_time;
}
// Check for the nospeak flag, Cel Nov 99
if(IS_SET(ch->in_room->room_flags, ROOM_NOSPEAK)
&& !HAS_CONFIG(ch, CONFIG_HOLYSPEECH)) {
ch->println("You feel the air escape your lungs, and yet... no sound.");
return;
}
// *** Find if we have a sayto victim
if (argument[0]=='>')
{
char to_arg[MIL];
argument++;
argument = one_argument( argument, to_arg);
victim = get_char_room( ch, to_arg);
if (!victim)
{
ch->printlnf("You can't find '%s' to 'say to'",to_arg);
return;
}
if (victim==ch)
{
ch->println("You can't direct your says at yourself.");
return;
}
if (victim->position ==POS_SLEEPING)
{
ch->printlnf("%s is asleep.",icapitalize(PERS(victim, ch)));
return;
}
if ( IS_NULLSTR(argument) )
{
ch->printlnf( "Say what to %s?", PERS(victim,ch));
return;
}
}
// parse the text
int splitbuf_index=0;// even index = say, odd = emote
bool in_emote=false; // true when we get a '[' but haven't yet seen a ']'
char *pstr;
char *writestr=&splitbuf[0][0]; // where the next character will go
bool trim_space=true; // used to trim the leading space off something
for(pstr=argument; !IS_NULLSTR(pstr); pstr++){
// trim of a single space from the start of each type
if(trim_space && *pstr==' '){
continue;
}
trim_space=false;
// $ are converted to $$ and then converted back to $ by act_new()
if(*pstr=='$'){
// double up the character into the appropriate buffer
*writestr++='$';
*writestr++='$';
continue;
};
// ` is converted to `` if convert colour is enabled
if(convert_colour && *pstr=='`'){
// double up the character into the appropriate buffer
*writestr++='`';
*writestr++='`';
continue;
};
// convert [[ into [
if(say_with_emotes){
if(*pstr=='[' && *(pstr+1)=='[' ){
*writestr++='[';
pstr++;
continue;
}
// convert ]] into ]
if(*pstr==']' && *(pstr+1)==']' ){
*writestr++=']';
pstr++;
continue;
}
}
// check for state changing characters
if(say_with_emotes && *pstr=='['){ // start emote
if(in_emote){
ch->printf("You can't have a [ character in a say after a [.\r\n"
" (to close the emote use a ]).\r\n"
" See `=Chelp saymote`x.\r\n");
ch->wrapln("hint: you can also disable the automated use of saymote "
"for the say command by typing `=Cautosaymote`x");
return;
};
splitbuf_index++;
if(splitbuf_index>=MAXBUFCOUNT){
ch->printlnf("There is a limit of %d alternating says + emotes in a saymote.",
MAXBUFCOUNT);
return;
};
in_emote=true;
*writestr='\0'; // terminate the buffer we were working on
//trim off last character in a say if it is a space
if(is_space(*(writestr-1))){
*(writestr-1)='\0'; // terminate the buffer trimming the last single
// space if necessary from the say
}
writestr=&splitbuf[splitbuf_index][0];
continue; // just switched into emote mode, go onto next character
}
if(say_with_emotes && *pstr==']'){ // close emote
if(!in_emote){
ch->println("You can't have a ] character before a matching [.\r\n"
" (to start an emote inside a say use a [).\r\n"
" See `=Chelp saymote`x.\r\n"
" To say an actual [ character, use [[.");
ch->wrapln("hint: you can also disable the automated use of saymote "
"for the say command by typing `=Cautosaymote`x");
return;
};
splitbuf_index++;
if(splitbuf_index>=MAXBUFCOUNT){
ch->printlnf("There is a limit of %d alternating says + emotes in a saymote.",
MAXBUFCOUNT);
return;
};
in_emote=false;
trim_space=true;// enable inital space trimming for next say
*writestr='\0'; // terminate the buffer we were working on
writestr=&splitbuf[splitbuf_index][0];
continue; // just switched into say mode, go onto next character
}
// copy the character into the appropriate buffer
*writestr++=*pstr;
}
// check that there isn't an open emote
if(in_emote){
ch->printf("You can't leave an open emote in a saymote.\r\n"
" See `=Chelp saymote`x.\r\n");
ch->wrapln("hint: you can also disable the automated use of saymote "
"for the say command by typing `=Cautosaymote`x");
return;
}
*writestr='\0'; // terminate the buffer we were working on
// *** decide if is relating to asking/saying and sayto
bool question=false;
bool exclaim=false;
for(i=0; i<=splitbuf_index; i+=2){
if(IS_NULLSTR(splitbuf[i])){
continue;
}
char *trimmedtext=rtrim_string(splitbuf[i]);
if(trimmedtext[str_len(trimmedtext)-1]=='?'){
question=true;
}else if(trimmedtext[str_len(trimmedtext)-1]=='!'){
exclaim=true;
}
break;
}
if (question){ // it is a question therefore asking
if(victim){
strcpy(tochar_sayask_text,"ask $N");
strcpy(toall_sayask_text,"asks $N");
strcpy(tovictim_sayask_text,"`#`Wasks you`&");
}else{
strcpy(tochar_sayask_text,"ask");
strcpy(toall_sayask_text,"asks");
}
}
else if (exclaim){
if(victim){
strcpy(tochar_sayask_text,"exclaim to $N");
strcpy(toall_sayask_text,"exclaims to $N");
strcpy(tovictim_sayask_text,"`#`Wexclaims to you`&");
}else{
strcpy(tochar_sayask_text,"exclaim");
strcpy(toall_sayask_text,"exclaims");
}
}
else
{ // saying
if(victim){
strcpy(tochar_sayask_text,"say to $N");
strcpy(toall_sayask_text,"says to $N");
strcpy(tovictim_sayask_text,"`#`Wsays to you`&");
}else{
strcpy(tochar_sayask_text,"say");
strcpy(toall_sayask_text,"says");
}
}
char format_buffer[MSL*2]; // *2 because the translator can expand text
int format_index;
char buf[MSL*2];
char wizitext[20];
bool langshow;
if(GAMESETTING3(GAMESET3_LANGUAGE_NAME_NOT_IN_SAYS)
|| language == language_unknown){
langshow=false;
}else{
langshow=true;
}
int max_invislevel=INVIS_LEVEL(ch);
if(victim){
max_invislevel=UMAX(INVIS_LEVEL(victim),max_invislevel);
}
if(max_invislevel){
sprintf(wizitext,"[Wizi %d] ", max_invislevel);
}else{
wizitext[0]='\0';
}
bool blind=false, deaf=false;
// translate the language to all/intended people? in the room
for( char_data *to= ch->in_room->people; to ; to = to->next_in_room )
{
if(IS_SET(sayflags, SAYFLAG_ONLY_REMEMBERED_CHAR) && to!=ch->mprog_target){
continue;
}
if (
(!IS_NPC(to) && to->desc == NULL) // linkdead or switched out of
|| ch==to // self
|| (IS_UNSWITCHED_MOB(to) && !IS_SET(to->act,ACT_MOBLOG)) // non switched mob
// without a moblog
|| !IS_AWAKE(to) ){ // asleep
continue;
}
// players can't see saymotes by wizi characters, or said to
// wizi characters
if (!IS_TRUSTED(to, max_invislevel)){
continue;
}
// set the deaf and blind for quick lookup
if(IS_IC(to)){
deaf=(is_affected(to, gsn_deafness ));
blind=(IS_AFFECTED( to, AFF_BLIND ) || is_affected( to, gsn_blindness ));
// someone that is deaf and blind gets nothing sent to them if IC
if(deaf && blind)
continue;
}
sprintf(format_buffer,"%s%s%s %s",
(IS_IMMORTAL(to)?wizitext:""), // [Wizi %d]
IS_OOC(ch)?"`B(OOC) `x":"`x", // (OOC)
PERS(ch, to), // ch->name/ch->short_descr
to==victim?tovictim_sayask_text:toall_sayask_text); // say/ask
// if there are more parts process them
for(format_index=0; format_index<=splitbuf_index; format_index++){
if(IS_NULLSTR(splitbuf[format_index]))
continue;
if(format_index%2==0){ // says are even
if(deaf){
sprintf(buf," `S<%s's lips move>`x", PERS(ch,to));
strcat(format_buffer,buf);
}else{
sprintf(&format_buffer[str_len(format_buffer)]," `x'`%c", ch->saycolour);
translate_language(language, langshow, ch, to, splitbuf[format_index], buf);
strcat(format_buffer, buf);
strcat(format_buffer,"`x'");// reset colour
}
langshow=false;
}else{ //emotes are odd
if(!blind){
sprintf(&format_buffer[str_len(format_buffer)]," `%c", ch->motecolour);
strcat(format_buffer,splitbuf[format_index]);
strcat(format_buffer,"`x");// reset colour
}
}
}
RECORD_TO_REPLAYROOM=true;
act( format_buffer, to, NULL, victim, TO_CHAR );
RECORD_TO_REPLAYROOM=false;
} // end of translation loop
{ // format what is sent to the actual speaker
// because this goes thru act() we don't need to put the [Wizi %d] on
if(IS_OOC(ch)){
if(IS_SET(language->flags,LANGFLAG_REVERSE_TEXT)){
sprintf(format_buffer,"`B(OOC) `xYou %s [reversing language]", tochar_sayask_text);
}else{
sprintf(format_buffer,"`B(OOC) `xYou %s", tochar_sayask_text);
}
}else{
if(GAMESETTING3(GAMESET3_LANGUAGE_NAME_NOT_IN_SAYS)
|| language == language_unknown)
{
sprintf(format_buffer,"`x%sYou %s",
(IS_IMMORTAL(ch)?wizitext:""), tochar_sayask_text);
}else{
sprintf(format_buffer,"`x%sYou %s in %s",
(IS_IMMORTAL(ch)?wizitext:""), tochar_sayask_text, language->name);
}
}
// if there are more parts process them
for(format_index=0; format_index<=splitbuf_index; format_index++){
if(IS_NULLSTR(splitbuf[format_index]))
continue;
if(format_index%2==0){ // says are even
sprintf(&format_buffer[str_len(format_buffer)]," `x'`%c", ch->saycolour);
strcat(format_buffer,splitbuf[format_index]);
strcat(format_buffer,"`x'");// reset colour
}else{ //emotes are odd
sprintf(&format_buffer[str_len(format_buffer)]," `%c", ch->motecolour);
strcat(format_buffer,splitbuf[format_index]);
strcat(format_buffer,"`x");// reset colour
}
}
RECORD_TO_REPLAYROOM=true;
act( format_buffer, ch, NULL, victim, TO_CHAR );
RECORD_TO_REPLAYROOM=false;
}
int number_in_room=ch->in_room->number_in_room;
// note: number_in_room is used to prevent a mobprog on two mobs in
// a room creating an endless loop by removing themself from
// the room and putting themselves back in the room - Kal, June 01
// handle mobprog speech and act triggers
if ( !IS_NPC(ch) && !IS_SET(sayflags, SAYFLAG_ONLY_REMEMBERED_CHAR) )
{
char_data *mob_next;
char_data *mob= ch->in_room->people;
for ( ; mob && --number_in_room>=0; mob = mob_next )
{
mob_next = mob->next_in_room;
if(!IS_NPC(mob)){
continue;
}
if (HAS_TRIGGER( mob, TRIG_SPEECH )
|| HAS_TRIGGER( mob, TRIG_ACT )
|| (HAS_TRIGGER( mob, TRIG_SAYTO) && victim==mob))
{
for(format_index=0; format_index<=splitbuf_index; format_index++){
if(IS_NULLSTR(splitbuf[format_index]))
continue;
if(format_index%2==0){ // says are even
if(HAS_TRIGGER( mob, TRIG_SAYTO))
{
mp_act_trigger( splitbuf[format_index], mob,
ch, NULL, NULL, TRIG_SAYTO );
}
if(HAS_TRIGGER( mob, TRIG_SPEECH ))
{
mp_act_trigger( splitbuf[format_index], mob,
ch, NULL, NULL, TRIG_SPEECH );
}
}else{ //emotes are odd
if(HAS_TRIGGER( mob, TRIG_ACT )){
mp_act_trigger( splitbuf[format_index], mob,
ch, NULL, NULL, TRIG_ACT );
}
}
}
}
}
}
}
/**************************************************************************/