/**************************************************************************/ // msp.cpp - msp support, Kerenos and Kal /*************************************************************************** * 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. * **************************************************************************/ #include "include.h" #include "msp.h" struct msp_table_type{ // the table using this type is sorted by MSP_TYPE char *base_url; // the base url of filename (including directory) char *prefix_filename; // directory it is stored in char *type; // the category of sound - players can turn off types int default_prority; // default priority of a sound int target_extra_prority;// extra priority of a sound when directed at a target int default_volume; // default volume of a sound to all in room int target_extra_volume;// extra volume of a sound to some it is targeted at }; msp_table_type msp_table[MSPT_MAX_TYPE]; struct msp_load_table_type { MSP_TYPES type_index; const char *directory; // used to create the base_url, prefix_filename and type int default_prority; // default priority of a sound int target_extra_prority;// extra priority of a sound when directed at a target int default_volume; // default volume of a sound to all in room int target_extra_volume;// extra volume of a sound to some it is targeted at }; msp_load_table_type msp_load_table_data[]= { // prorities , volumes { MSPT_ACTION, MSP_ACTION_DIR, 40, 10, 60, 15 }, { MSPT_COMBAT, MSP_COMBAT_DIR, 65, 20, 60, 35 }, { MSPT_MOBPROG, MSP_MOBPROG_DIR, 35, 40, 50, 30 }, { MSPT_ROOM, MSP_ROOM_DIR, 45, 0, 70, 0 }, { MSPT_SKILL, MSP_SKILLS_DIR, 60, 10, 50, 35 }, { MSPT_SPELL, MSP_SPELLS_DIR, 60, 10, 50, 35 }, { MSPT_WEATHER, MSP_WEATHER_DIR, 25, 0, 60, 0 }, { MSPT_MAX_TYPE, "", 0, 0, 0, 0 }// end of table marker }; /**************************************************************************/ char * get_msptype_name(const char *word) { static char rbuf[3][MIL]; static int index; char *pStr; ++index%=3; // rotate return buffer sprintf(rbuf[index], "%s", word); pStr=&rbuf[index][0]; // convert spaces into _ characters // and upper to lowercase do{ if (*pStr==' '){ *pStr='_'; }else if (*pStr=='/'){ *pStr='_'; }else{ *pStr=tolower(*pStr); } }while (*(++pStr)); // trim off any tailing _ if(*(pStr-1)=='_'){ *(pStr-1)='\0'; } return rbuf[index]; } /**************************************************************************/ // change any '\' into a '/' void backslash_to_slash(char *word) { char *pStr=word; do{ if (*pStr=='\\'){ *pStr='/'; } }while (*(++pStr)); } /**************************************************************************/ // Kal - Dec 99 void msp_load_table() { #define data_table msp_load_table_data[i] #define tab_element msp_table[msp_load_table_data[i].type_index] int i; for (i=0; !IS_NULLSTR(data_table.directory); i++){ tab_element.base_url = str_dup(MSP_URL); tab_element.prefix_filename = str_dup(data_table.directory); tab_element.type = str_dup(get_msptype_name(data_table.directory)); // the prorities and volumes tab_element.default_prority = data_table.default_prority; tab_element.target_extra_prority= data_table.target_extra_prority; tab_element.default_volume = data_table.default_volume; tab_element.target_extra_volume = data_table.target_extra_volume; } #undef tab_element #undef data_table logf("msp_load_table(): msp_table loaded with msp type info."); } /**************************************************************************/ float get_yellreduction(short sector); /**************************************************************************/ // Sends an msp sound to everyone in the room - Kal, Dec 99 // NOTES: // * if the volume is zero, the default volume is used for the sound type // * repeats = number of times to play the sound // * If surrounding_rooms is true, you can hear the sound in the // surrounding rooms (go figure) // * If the extension of the sound filename is .mid then !!MUSIC is used void msp_to_room(MSP_TYPES type, char *filename, int volume, // 1 ->100, if 0 default for type vol used char_data *target, bool target_only_in_room, bool surrounding_rooms) { if(IS_NULLSTR(filename)){ return; } char msp_trigger_format_buf[MSL]; char_data *to; // handle the loading of the msp_table on its first use static bool msp_table_needs_loading=true; if(msp_table_needs_loading){ msp_load_table(); msp_table_needs_loading=false; } // get the filename of what we are sending, check the file is on the server char send_filename[MSL]; // support system if last character in the filename before the extension is a digit // the sound will be randomized, with filename0.wav->filename#.wav where # is // the value of that digit int len=str_len(filename); if( len>5 && is_digit(filename[len-5]) && !str_suffix(".wav", filename) ) { // get a random sound file - if not found drop back to '*0.wav' filename[len-5]=(char)number_range('0', filename[len-5]); if(GAMESETTING(GAMESET_MSP_CHECK_FILEEXIST)){ if(!file_exists(MSP_DIR "%s%s", msp_table[type].prefix_filename, filename)){ filename[len-5]=(char)'0'; } } } sprintf(send_filename, "%s%s", msp_table[type].prefix_filename, filename); if(GAMESETTING(GAMESET_MSP_CHECK_FILEEXIST)){ if(!file_exists(MSP_DIR "%s", send_filename)){ bugf("msp_to_room(): couldn't find sound to send - send_filename = '%s'", send_filename); return; }; } // check our target and its room is valid if(target==NULL || target->in_room==NULL){ bugf("msp_to_room(): target==NULL || target->in_room==NULL! - send_filename = 'msp "DIR_SYM"%s'", send_filename); return; } // get the default volume if(volume==0){ volume=msp_table[type].default_volume; } if(volume>100){ volume=100; } //construct the unchanging parts of the msp trigger if(!str_suffix( ".mid", send_filename)){ sprintf(msp_trigger_format_buf, "!!MUSIC(%s V=%%d L=1 T=%s", send_filename, msp_table[type].type); }else{ sprintf(msp_trigger_format_buf, "!!SOUND(%s V=%%d L=1 P=%%d T=%s", send_filename, msp_table[type].type); } // if the url is sufficient length, has been changed from the default, we use it. if(!IS_NULLSTR(msp_table[type].base_url) && str_len(msp_table[type].base_url)>5 && strcmp(DEFAULT_MSP_URL,msp_table[type].base_url)) { strcat(msp_trigger_format_buf, FORMATF(" U=%s%s", msp_table[type].base_url, send_filename)); } strcat(msp_trigger_format_buf,")"); // convert any backslashes to slashes backslash_to_slash(msp_trigger_format_buf); // send to the target if(CAN_HEAR_MSP(target)) { flush_char_outbuffer(target); target->printf(msp_trigger_format_buf, ((volume+msp_table[type].target_extra_volume)>100? 100:(volume+msp_table[type].target_extra_volume)), (msp_table[type].default_prority+msp_table[type].target_extra_prority)); } if(!target_only_in_room){ // send to all in room except target for(to = target->in_room->people; to; to=to->next_in_room ){ if (to!=target && CAN_HEAR_MSP( to )){ flush_char_outbuffer(to); to->printf(msp_trigger_format_buf, volume, msp_table[type].default_prority); } } } if(!surrounding_rooms){ return; } // do the sending to all surrounding rooms ROOM_INDEX_DATA *from_room=target->in_room; for ( int door = 0; door < MAX_DIR; door++ ) { EXIT_DATA *pexit; int main_volume=volume; if ( ( pexit = from_room->exit[door] ) != NULL && pexit->u1.to_room != NULL && pexit->u1.to_room != from_room) { // get the new volume - same volume reduction as yelling // - reduction should technically be logarithmic, but life goes on :) volume=(int)((float)main_volume * get_yellreduction(pexit->u1.to_room->sector_type)); if(IS_SET(from_room->exit[door]->exit_info,EX_CLOSED)){ volume=main_volume/2; // closed doors make things quieter } // send to all in room except target for(to = pexit->u1.to_room->people; to; to=to->next_in_room ){ if (CAN_HEAR_MSP( to )){ flush_char_outbuffer(to); to->printf(msp_trigger_format_buf, volume, msp_table[type].default_prority/2); } } } } } /**************************************************************************/ // plays a skills sound if it has one set in sedit void msp_skill_sound(char_data *target, int sn) { if(!IS_NULLSTR(skill_table[sn].msp_sound)){ msp_to_room(MSPT_SKILL, skill_table[sn].msp_sound, 0,target, false, true); } } /**************************************************************************/ void do_msp( char_data *ch, char *argument ) { pc_data *pcdata=TRUE_CH(ch)->pcdata; // the characters pcdata we want to work on if(!pcdata){ ch->println("Players can only use this command"); return; } if(IS_NULLSTR(argument)){ ch->titlebar("MUD SOUND PROTOCOL OPTIONS"); ch->println("syntax: `=Cmsp off`x - msp is permanately off."); ch->wrapln("syntax: `=Cmsp auto`x - mud will attempt to automatically " "detect if you have mud client that supports msp, if one is detected " "the mud will send you msp sound triggers"); ch->wrapln("syntax: `=Cmsp on`x - msp is permanately on, mud will send you sound " "triggers even if your mud client doesn't support msp."); ch->printlnf("Your msp preference is currently set to %s", preference_word(pcdata->preference_msp)); if(pcdata->preference_msp==PREF_AUTOSENSE){ ch->printlnf("Your connections msp support has %sbeen automatically detected.", (ch->desc && IS_SET(ch->desc->flags, CONNECTFLAG_MSP_DETECTED))?"":"not "); } ch->titlebar(""); return; } PREFERENCE_TYPE pt; if(!str_prefix(argument, "off")){ pt=PREF_OFF; }else if(!str_prefix(argument, "autosense")){ pt=PREF_AUTOSENSE; }else if(!str_prefix(argument, "on")){ pt=PREF_ON; }else{ ch->printlnf("Unsupported msp option '%s'", argument); do_msp(ch,""); return; } if(pcdata->preference_msp==pt){ ch->printlnf("Your msp preference is already set to %s", preference_word(pt)); return; } ch->printlnf("msp preference changed from %s to %s", preference_word(pcdata->preference_msp), preference_word(pt)); pcdata->preference_msp=pt; msp_update_char(ch); } /**************************************************************************/ void msp_update_char(char_data*ch) { if(!ch){ return; } pc_data *pcdata=TRUE_CH(ch)->pcdata; connection_data *d=TRUE_CH(ch)->desc; if(!pcdata || !d){ return; } switch(pcdata->preference_msp){ case PREF_OFF: pcdata->msp_enabled=false; break; case PREF_AUTOSENSE: if(IS_SET(d->flags,CONNECTFLAG_ANSWERED_MSP) && IS_SET(d->flags,CONNECTFLAG_MSP_DETECTED)){ pcdata->msp_enabled=true; }else{ pcdata->msp_enabled=false; } break; case PREF_ON: pcdata->msp_enabled=true; break; } } /**************************************************************************/