sunder2.1a/clan/
sunder2.1a/class/
sunder2.1a/class/bak/
sunder2.1a/doc/ideas/
sunder2.1a/gods/
sunder2.1a/i3/
sunder2.1a/log/
sunder2.1a/msgbase/
sunder2.1a/player/
sunder2.1a/src/o/
sunder2.1a/time/
/**********************************************************
 *************** S U N D E R M U D *** 2 . 0 **************
 **********************************************************
 * The unique portions of the SunderMud code as well as   *
 * the integration efforts for code from other sources is *
 * based primarily on the efforts of:                     *
 *                                                        *
 * Lotherius <aelfwyne@operamail.com> (Alvin W. Brinson)  *
 *    and many others, see "help sundermud" in the mud.   *
 **********************************************************/

#include "everything.h"

/*
 * In this file, always check for MSP/MXP before checking for Pueblo.
 * 
 * The reason? Newer ZMuds "support" pueblo. However, if you use Pueblo commands,
 * most of them are broken and behave very badly. zMud returns a Puebloclient string,
 * however, which results in lots of broken things that would've worked just fine with
 * the MXP code. Lesson: Check for MXP before checking for Pueblo.
 */

/*
 * Function to strip linefeed. Because ZMud barfs with <SEND></SEND> on a simple linefeed.
 */

char *strip_lf ( char *str )
{
     static char         newstr[MAX_STRING_LENGTH];
     int                 i, j;
     
     for ( i = j = 0; str[i] != '\0'; i++ )
          if ( str[i] != '\n' )
          {
               newstr[j++] = str[i];
          }
     newstr[j] = '\0';
     return newstr;
}


/* Sound Stuff */

void do_sound ( CHAR_DATA * ch, char *argument )
{
     char arg[MAX_STRING_LENGTH];

     if ( IS_NPC(ch) || !ch->desc )
          return;

     argument = one_argument ( argument, arg );
          
     if ( !ch->desc->msp && !ch->desc->mxp && !ch->desc->pueblo )
     {
          ch->desc->msp = TRUE;
          send_to_char ( "Attempting to enable MSP sound. Note: Pueblo and MXP clients do not need to enable sound via this command.\n\r\n\r", ch );
          send_to_char ( "!!SOUND(off U=" TXT_SOUNDURL ")",ch );
          send_to_char ( "!!MUSIC(off U=" TXT_SOUNDURL ")",ch );
          send_to_char ( "\n\rIf you have an older version of Zmud you must read {Whelp MSP{w\n\r", ch);
          send_to_char ( "for information on how to install sounds. Other clients may vary.\n\r", ch);
          send_to_char ( "{WMSP sound is on. You must have an MSP client. (Help MSP)\n\r", ch );
          send_to_char ( "Now showing the sound control panel:\n\r\n\r", ch);
          ch->pcdata->svolume = 75;
          ch->pcdata->mvolume = 50;
     }     
     if ( !str_cmp ( arg, "off" ) )
     {
          if ( ch->desc->mxp )
          {
               send_to_char ( "Cannot disable sound in MXP completely, but we will set the volume to Zero.\n\r", ch );
               ch->pcdata->mvolume = 0;
               ch->pcdata->svolume = 0;
          }
          else if ( ch->desc->pueblo )
          {
               send_to_char ( "Please disable sound in your client with Pueblo.\n\r", ch );
          }
          else if ( ch->desc->msp )
          {
               send_to_char ( "Sound is now off.\n\r", ch );
               send_to_char ( "!!SOUND(off)",ch );
               send_to_char ( "!!MUSIC(off)",ch );
               ch->desc->msp = FALSE;
          }
          else
          {
               send_to_char ( "You don't have sounds enabled to begin with.\n\r", ch );
               return;
          }
          send_to_char ( "\n\rIf you prefer, the \"stop\" command will stop the current sound and leave sound on.\n\r", ch);
          return;
     }

     if ( !str_cmp ( arg, "m" ) || !str_cmp (arg, "music") )
     {
          if ( atoi(argument) < 0 || atoi(argument) > 100)
          {
               send_to_char ("Volume values range from 0 (Off) to 100\%\n\r", ch);
               return;
          }
          form_to_char ( ch, "Music volume: %d\n\r", atoi(argument) );
          ch->pcdata->mvolume = atoi(argument);

          return;
     }

     if ( !str_cmp ( arg, "s" ) || !str_cmp (arg, "sounds") )
     {
          if ( atoi(argument) < 0 || atoi(argument) > 100)
          {
               send_to_char ("Volume values range from 0 (Off) to 100\%\n\r", ch);
               return;
          }
          form_to_char ( ch, "Sound Effects volume: %d\n\r", atoi(argument) );
          ch->pcdata->svolume = atoi(argument);
          return;
     }
     
     form_to_char ( ch, "{G[{W---{G]{w Music              {G[{W---{G]{w Sound Effects\n\r");
     send_to_char (     "----------------------------------------------\n\r", ch);
     form_to_char ( ch, "{G[{W%3s{G]{w (m) Music Volume   {G[{W%3s{G]{w (s) Sounds Volume\n\r",
                    ( ch->pcdata->mvolume > 0 ? itos(ch->pcdata->mvolume) : "OFF" ),
                    ( ch->pcdata->svolume > 0 ? itos(ch->pcdata->svolume) : "OFF" ) );
     send_to_char (     "----------------------------------------------\n\r", ch);
     send_to_char("Syntax: sound <type> <vol>\n\r    (Enter 0 for \"OFF\", type is \"m\" or \"s\")\n\r", ch);
     if ( ch->desc->msp )
          send_to_char("Use \"sound off\" to turn MSP off completely.\n\r", ch);
     return;
}

void do_stop ( CHAR_DATA *ch)
{
     if (IS_NPC(ch) || !ch->desc)
          return;
     else if ( ch->desc->pueblo )
     {
          send_to_char ( "<img xch_sound=stop>", ch );
          send_to_char ( "Currently playing sounds and music halted.\n\r", ch);               
     }
     else if ( ch->desc->mxp )
     {
          send_to_char ( MXP_SECURE "<SOUND off><MUSIC off>" MXP_LLOCK, ch );
          send_to_char ( "Currently playing sounds and music halted.\r\n", ch );
     }
     else if ( ch->desc->msp )
     {
          /* We're not going to clear "playing" because we don't want to restart the song yet. */
          send_to_char ( "!!SOUND(off)",ch );
          send_to_char ( "!!MUSIC(off)",ch );
          send_to_char ( "Currently playing sounds and music halted.\n\r", ch);
     }
     else     
          send_to_char("You don't have sound enabled...\n\r", ch);     
     return;
}

// Stops music on a desc with no visible output.
void stop_music ( DESCRIPTOR_DATA *d )
{
     if ( d->pueblo )
     {
          send_to_desc ( d, "<img xch_sound=stop>" );
          return;
     }
     else if ( d->mxp )
     {
          send_to_desc ( d, MXP_SECURE "<MUSIC off>" MXP_LLOCK );
          return;
     }
     else if ( d->msp )
     {
          send_to_desc ( d, "!!MUSIC(off)" );
          return;
     }
     return;
}

/* Call this with: filename, ch */
/* eventually add sound classes */

void sound ( const char *fname, CHAR_DATA *ch )
{
     if ( IS_NPC(ch) || !ch->desc )
          return;

     if ( ch->desc->mxp )
     {
          form_to_char ( ch, MXP_SECURE "<SOUND %s V=%d U=" TXT_SOUNDURL ">" MXP_LLOCK, fname, ch->pcdata->svolume );
     }
     else if ( ch->desc->pueblo )
     {
          form_to_char ( ch, "</xch_mudtext><img xch_volume=%d xch_device=wave>", ch->pcdata->svolume );
          form_to_char ( ch, "<img xch_sound=play href=\"" TXT_SOUNDURL "%s\"><xch_mudtext>", fname );
     }
     else if ( ch->desc->msp )
     {
          // URL Tag is from V.3 specification. V.2 spec doesn't have it.
          form_to_char ( ch, "!!SOUND(%s V=%d U=" TXT_SOUNDURL "%s)", fname, ch->pcdata->svolume, fname );
     }

     return;
}

void music ( const char *fname, CHAR_DATA *ch, bool repeat )
{
     if ( IS_NPC(ch) || !ch->desc )
          return;
     
     if ( !ch->desc->msp && !ch->desc->pueblo && !ch->desc->mxp )
          return;

     /* Let's not repeat the same thing over and over. */
     /* This saves bandwidth, and keeps a song that has been stopped from playing */
     
     if ( !str_cmp ( fname, ch->pcdata->mplaying ) )
          return;
     
     free_string ( ch->pcdata->mplaying );
     ch->pcdata->mplaying = str_dup ( fname );
     
     if (repeat)
     {
          if ( ch->desc->mxp )          
               form_to_char ( ch, MXP_SECURE "<MUSIC %s V=%d L=-1 C=1 U=" TXT_SOUNDURL ">" MXP_LLOCK, fname, ch->pcdata->mvolume );
          else if ( ch->desc->pueblo )
          {
               form_to_char ( ch, "</xch_mudtext><img xch_volume=%d xch_device=midi>", ch->pcdata->mvolume );
               form_to_char ( ch, "<img xch_sound=loop href=\"" TXT_SOUNDURL "%s\"><xch_mudtext>", fname );
          }
          else if ( ch->desc->msp )
               form_to_char ( ch, "!!MUSIC(%s V=%d L=-1 C=1 U=" TXT_SOUNDURL "%s)", fname, ch->pcdata->mvolume, fname );
          
     }
     else
     {
          if ( ch->desc->mxp )
               form_to_char ( ch, MXP_SECURE "<MUSIC %s V=%d C=1 U=" TXT_SOUNDURL ">" MXP_LLOCK, fname, ch->pcdata->mvolume );
          else if ( ch->desc->pueblo )
          {
               form_to_char ( ch, "</xch_mudtext><img xch_volume=%d xch_device=midi>", ch->pcdata->mvolume );
               form_to_char ( ch, "<img xch_sound=play href=\"" TXT_SOUNDURL "%s\"><xch_mudtext>", fname );
          }
          else if ( ch->desc->msp )
               form_to_char ( ch, "!!MUSIC(%s V=%d C=1 U=" TXT_SOUNDURL "%s)", fname, ch->pcdata->mvolume, fname );

     }
     return;
}

// Sets up MXP
//
// If you have any entities to declare, put them here.
// But keep in mind, colors don't translate in entities correctly... Grr...
//

void mxp_init ( DESCRIPTOR_DATA *d )
{
    char buf[MSL];
    
    SNP ( buf, MXP_SECURE
           "<!ELEMENT RName '<FONT \"Comic Sans MS\" COLOR=CYAN> <B>' FLAG=\"RoomName\">"
           "<!ELEMENT RDesc FLAG='RoomDesc'>"
           "<!ELEMENT RExits FLAG='RoomExit'>"
           "<!ELEMENT Ex '<SEND>'>" );
    write_to_buffer ( d, buf, 0 );
    SNP ( buf, MXP_SECURE "<SUPPORT image send frame stat>" );
    write_to_buffer ( d, buf, 0 );
    SNP ( buf, MXP_LLOCK ); // Locked mode, no player MXP tags..... 
    //     if ( d->pueblo )
    //          write_to_buffer ( d, "<xch_mudtext>", 0 );
    //  
    write_to_buffer ( d, buf, 0 );
    
    return;
}

/*
 * Argument is the pathname of the image to display.
 * 
 * Bitmap or GIF (why no PNG support in the clients???)
 *
 * if pageit is true, the text will be paged rather than sent.
 * 
 * Argh.... ZMud displays PUEBLO images just fine, but fuxors its own format!
 * 
 */

void inline_image ( DESCRIPTOR_DATA *d, char *image, char *align, bool pageit )
{
     char buf[MSL];

     if ( d->mxp )
     {
          SNP ( buf, "<IMAGE FName=\"%s\" URL=\"" TXT_IMAGEURL "\" ALIGN=\"%s\">",
                strip_cr(strip_lf(image)), align );
          
          if ( pageit )
          {
               if ( !d->character )
               {
                    bugf( "No character on inline_image paged call." );
                    return;
               }
               page_to_char ( MXP_SECURE, d->character );
               page_to_char ( buf, d->character );
               page_to_char ( MXP_LLOCK, d->character );
          }
          else
          {
               send_to_desc ( d, MXP_SECURE );
               send_to_desc ( d, buf );
               send_to_desc ( d, MXP_LLOCK );
          }
     }
     else if ( d->pueblo && !d->mxp ) // VEry careful NOT to use Pueblo if we have MXP since ZMUD Barfs on Pueblo "emulation"
     {
          SNP ( buf, "<img src=\"" TXT_IMAGEURL "%s\" align=%s>", image, align );
          if ( pageit )
          {
               if ( !d->character )
               {
                    bugf( "No character on inline_image paged call." );
                    return;
               }
               page_to_char ( "</xch_mudtext>", d->character );
               page_to_char ( buf, d->character );
               page_to_char ( "<xch_mudtext>", d->character );
          }
          else
          {
               send_to_desc ( d, "</xch_mudtext>" );
               send_to_desc ( d, buf );
               send_to_desc ( d, "<xch_mudtext>" );
          }
     }
     return;
}

// Allows user to specify an image to display to self from the default location.

void do_image ( CHAR_DATA *ch, char *argument )
{
     inline_image ( ch->desc, argument, "bottom", FALSE );
}

/*
 * Sends an appropriate client tag to center text.
 *
 * Not only does MXP not have a <center> tag that I can find,
 * it also refuses to properly display the Pueblo tag through
 * its compatibility mode. So, no MXP clients get the tag.
 */

void tag_center ( DESCRIPTOR_DATA *d, bool onoff, bool pageit )
{
     char buf[MSL];

     if ( !d->pueblo )
          return;
     
     if ( onoff ) // True = turn centering on.
     {
          if ( d->pueblo && !d->mxp )
          {
               SNP ( buf, "</xch_mudtext><center><xch_mudtext>" );
          }
     }
     else // False = turn centering off.
     {
          if ( d->pueblo && !d->mxp )
          {
               SNP ( buf, "</xch_mudtext></center><xch_mudtext>" );
          }
     }
     if ( pageit ) // Can only page to a char
     {
          if ( !d->character )
          {
               bugf ( "No character on tag_center paged call." );
               return;
          }
          page_to_char ( buf, d->character );
     }
     else
          send_to_desc ( d, buf );
     
     return;
}

/*
 * Opens a "secure" channel for tags.
 * Implemented as char so it can be embedded in other text.
 */
char                         *tag_secure ( DESCRIPTOR_DATA *d )
{
    static char                   buf[128];
    
    buf[0] = '\0';
    
    if ( d->mxp )
        SLCAT ( buf, MXP_SECURE );
    else if ( d->pueblo )
        SLCAT ( buf, "</xch_mudtext>" );
    else
        SLCAT ( buf, "" );
    
    return buf;
}

/*
 * Closes secure tag channel
 * Implemented as char so it can be embedded in other text.
 */
char                         *tag_close ( DESCRIPTOR_DATA *d )
{
    static char                   buf[128];
    
    buf[0] = '\0';
    
    if ( d->mxp )
        SLCAT ( buf, MXP_LOPEN ); /* We're going to use locked open mode now. */
    else if ( d->pueblo )
        SLCAT ( buf, "<xch_mudtext>" );
    else
        SLCAT ( buf, "" );
    return buf;
}



/*
 * Returns a wrapped string that is clickable.
 * 
 * Unfortunately, Pueblo doesn't support a drop-down menu like MXP so this only allows one item.
 */

char *click_cmd ( DESCRIPTOR_DATA *d, char *text, char *command, char *mouseover )
{
     static char buf[MSL];
     
     buf[0] = '\0';

     if ( d->mxp )
     {
          SNP ( buf, MXP_SECURE "<send \"%s\" hint=\"%s\">%s</SEND>" MXP_LLOCK, command, mouseover, strip_cr(strip_lf(text)) );
     }
     else if ( d->pueblo )
     {
          SNP ( buf, "</xch_mudtext><a xch_cmd=\"%s\" xch_hint=\"%s\">%s</a><xch_mudtext>", command, mouseover, text );
     }
     else
     {
          SNP ( buf, text );
     }

     return buf;
}