Alright all, well I decided I wanted bards in my MUD...bards that could play
music on instruments (mainly magical) and have affects take place, or damage
done to enemies.  This is my song system, which is basically a rip of the spell
system, only a LOT less complicated, and alot smaller also.  Also, the way _I_
have it setup, you dont practice every different song to get better at it,
you have one skill called music that takes a tons of practices to get, and
you aquire songs at certain levels and can then play them.  I also have spell
components on my MUD, and one advantage songs have over normal spells is they
don't take components.  Songs should therefore take a LOT of mana to play.  Songs
can pretty much do anything you want them to (writing a song function is like
writing a magic spell function with less parameters since I don't have targets,
but that could easily be added in).  I make all defensive songs affect all
players in the room, and all offensive songs only harm mobs in the room.  I have
included a sample song in the song table, as well as the function for it.  My
mud is dragonlance based, hence the "Song of Huma".  Anyway, if you find any bugs
and whatnot, or you have compliments, criticisms, etc, email them to fire@gdi.net.
-Chaos

P.S.  I put this installation guide together about 10 minutes ago in about 6 minutes.
	it SHOULD work but i make no guarantees, and I dont take responsibility
	for anything bad it causes (Although nothing bad should happen, and it works
	fine on my computer).  Also I wrote this code in about 1 hour last night so
	its not the best code I know, but gimme a break ill be fixing it up over the
	next week or so.  Other than that, enjoy :)


And now, without further ado, installation instructions for music.c (this replaces
the old music system of ROM for me so i made it music.c, you may want to change the
filename if you still use ROM's music system.

In merc.h::::::::::

	Just under
		#define DECLARE_SPELL_FUN( fun )        void fun( )

	put
		#define DECLARE_SONG_FUN( fun )         void fun( )



	Just under
		#define DECLARE_SPELL_FUN( fun )        SPELL_FUN fun

	put
		#define DECLARE_SONG_FUN( fun )         SONG_FUN  fun


	Just under
		typedef void SPELL_FUN  args( ( int sn, int level, CHAR_DATA *ch, void *vo,
                                int target ) );

	put
		typedef void SONG_FUN   args( ( int songnum, int level, CHAR_DATA *ch ) );

	In the defines for MAX_WHATEVER, add
		#define MAX_SONGS		1 (or however many songs you have written)

	Down in the various structs, add

		struct song_type
		{
    		    char *      name;                   /* Name of song */
    		    char *      listname;               /* name that shows on do_songs */
    		    sh_int      level;                  /* Average of player vs instrument */
    		    SONG_FUN *  song_fun;               /* function called for song */
		    sh_int      minimum_position;       /* min position to play song */
    		    sh_int      min_mana;               /* min mana song takes */
    		    sh_int      beats;                  /* Waiting time after use */
		};


	In the extern constant declarations add:
		extern  const   struct  song_type       song_table      [MAX_SONGS];

	in the GSN declarations add gsn_music

	you will need an item of type instrument that a player can hold to play music,
	so in the ITEM_ section (same section as ITEM_WARP_STONE) add 
		#define ITEM_INSTRUMENT ## (free number)

In const.c::::::::::::::::

	Add a music skill, should look like this

	{
            "music",                {1, 1, 1, 1}, {20, 20, 20, 20}
            spell_null,             TAR_IGNORE,             POS_RESTING,
            &gsn_music,             SLOT(0),        0,      5,
            "",                     "!music!",      ""
        }

	in the ITEM_TYPE struct, add
		{	ITEM_INSTRUMENT,	"instrument"	},

In db.c::::::::::::::

	in the sh_int's for gsn's, add
		sh_int		gsn_music;

	under case ITEM_TREASURE:

	add
		case ITEM_INSTRUMENT:

In tables.c::::::::::::::

	in the type_flags structure, add

	{	"instrument",	ITEM_INSTRUMENT,	TRUE	},


In interp.h::::::::::::::
	add in the declares
		DECLARE_DO_FUN(	do_play		);
		DECLARE_DO_FUN(	do_songs	);

In interp.c:::::::::::::::
	add in two new commands just like the others,

	{ "play",	do_play,	POS_RESTING,	0,	LOG_NORMAL, 1 },
	{ "songs",	do_songs,	POS_DEAD,	0,	LOG_NORMAL, 1 },

Cut below here on the line, save the file as whatever.c, and add whatever.o to your
makefile (ie if you keep this file music.c, then add music.o into your makefile.

Compile, and you should have a (hopefully) bugfree, WORKING version of bard songs...
of course this goes best with a bard CLASS, so I suggest making one....If any of you
want to see this in action it is on my MUD, Realm of the Lance, which isnt accepting
players yet but will be soon...hope to see some of you there soon.
	

-------------------------Cut here for music.c------------------------------
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  In particular, you may not remove either of *
 *  these copyright notices.                                               *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

/***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
*       ROM has been brought to you by the ROM consortium                  *
*           Russ Taylor (rtaylor@hypercube.org)                            *
*           Gabrielle Taylor (gtaylor@hypercube.org)                       *
*           Brian Moore (zump@rom.org)                                     *
*       By using this code, you have agreed to follow the terms of the     *
*       ROM license, in the file Rom24/doc/rom.license                     *
***************************************************************************/

/**************************************************************************
***************************************************************************
***************************************************************************
***									***
***	This file is for bard songs, and the music and play skill,	***
***	written from scratch by me (Chaos) for the Realm of the lance	***
***	MUD, copyright 1998.  It may be used as long as this header	***
***	file remains intact, and my name is mentioned somewhere in the	***
***	help file for music/play.  I would also appreciate an e-mail	***
***	stating that you are using this and the address of your mud	***
***	so I can come check it out!  Any comments or suggestions, or	***
***	bugs may be e-mailed to chaos@lance.betterbox.net.  Enjoy!	***
***									***
***************************************************************************
***************************************************************************
**************************************************************************/

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "merc.h"

/*
 * These are the declares for the song_fun's
 * Add new declares for new songs you write here
 */
DECLARE_SONG_FUN(	song_of_huma		);

/*
 * Table for the songs of the MUD
 * add a new set of brackets for each new song you add, and dont forget
 * to increment MAX_SONGS in merc.h
 */
const   struct  song_type       song_table [MAX_SONGS] =
{
/*  {
	"Song name", "Song list name", level, song_fun,
	min position, min mana, beats
    }
*/
    {
        "song of huma", "Song of Huma", 20, song_of_huma,
	POS_RESTING, 40, 25
    }
};


/* This function lists songs and their levels...the {Y and {G stuff is for color
 * remove it if you dont have color
 */
void do_songs(CHAR_DATA *ch, char *argument)
{
    char buf[MAX_STRING_LENGTH];
    int i;

    sprintf(buf, "{Y[%-18s %5s]{x\n\r", "Song Name", "Level");
    send_to_char(buf,ch);

    for (i = 0; i < MAX_SONGS; i++)
    {
	sprintf(buf, "{Y[{G%-20s {C%3d{Y]{x\n\r", song_table[i].listname, song_table[i].level);
	send_to_char(buf,ch);
    }
    return;
}


/* looks up a song */
int song_lookup( const char *name )
{
    int songnum;

    for ( songnum = 0; songnum < MAX_SKILL; songnum++ )
    {
	if ( song_table[songnum].name == NULL )
	    break;
	if ( LOWER(name[0]) == LOWER(song_table[songnum].name[0])
	&&   !str_cmp( name, song_table[songnum].name ) )
	    return songnum;
    }

    return -1;
}


/* actually starts the playing process */
void do_play( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *instrument;
    int songnum, chance, mana, level;

    if ((chance = get_skill(ch,gsn_music)) == 0)
    {
	send_to_char("You have no clue how to play music.\n\r", ch);
	return;
    }

    if ((instrument = get_eq_char(ch, WEAR_HOLD)) == NULL)
    {
	send_to_char("You aren't carrying an instrument.\n\r", ch);
	return;
    }

    if (instrument->item_type != ITEM_INSTRUMENT)
    {
	send_to_char("You aren't carrying an instrument.\n\r", ch);
	return;
    }

    if (argument[0] == '\0')
    {
	send_to_char("Play what?\n\r", ch);
	return;
    }

    songnum = song_lookup(argument);

    if (songnum == -1)
    {
	send_to_char("That isn't a song.\n\r", ch);
	return;
    }

    if (ch->level < song_table[songnum].level)
    {
	send_to_char("You haven't been able to master that song yet.\n\r", ch);
	return;
    }

    /*
	Below:  This basically lets there be songs that you can play while resting
	and songs that must be standing to play.  This way you cant play a damaging
	song to start a fight while sitting/resting
    */

    if (ch->position < song_table[songnum].minimum_position)
    {
	send_to_char("You need to be standing up to play that song.\n\r", ch);
	return;
    }

    /*
	Below: This can be changed to an algorith to allow for varied mana
	based on a comparison to level of spell vs players level, etc
    */

    mana = song_table[songnum].min_mana;

    if (!IS_NPC(ch) && ch->mana < mana)
    {
	send_to_char("You don't have enough mana.\n\r", ch);
	return;
    }

    act("$n plays a melody on $s $p.",ch,instrument,NULL,TO_ROOM);
    act("You play a melody on your $p.",ch,instrument,NULL,TO_CHAR);

    WAIT_STATE( ch, song_table[songnum].beats );

    chance = chance - (20 / (1 + ch->level - song_table[songnum].level));

	/* average of level of player and level of instrument */
    level = (ch->level + instrument->level) / 2;

    if (number_percent() > chance)
    {
	ch->mana -= mana / 2;
	act("$n's fingers slip and the song ends abruptly.",ch,NULL,NULL,TO_ROOM);
	send_to_char("Your fingers slip and the song ends abruptly.\n\r", ch);
	check_improve(ch,gsn_music,FALSE,1);
	return;
    }
    else /* actually start playing the song */
    {
	ch->mana -= mana;
	if (IS_NPC(ch) || class_table[ch->class].fMana)
	    (*song_table[songnum].song_fun) ( songnum, level, ch );
	else
	    (*song_table[songnum].song_fun) ( songnum, 3 * level/4, ch );
	check_improve(ch,gsn_music,TRUE,1);
    }

    return;
}


/* SAMPLE SONG! This song casts armor and bless on the player, and theres
   an 80% chance for each spell for each person in the room that they will
   receive the effect also
*/

void song_of_huma( int songnum, int level, CHAR_DATA *ch )
{
    CHAR_DATA *vch;
    AFFECT_DATA af1, af2;

    af1.where = TO_AFFECTS;
    af1.type = skill_lookup("bless");
    af1.level = level;
    af1.duration = level/2;
    af1.location = APPLY_HITROLL;
    af1.modifier = level/8;
    af1.bitvector = 0;

    af2.where = TO_AFFECTS;
    af2.type = skill_lookup("armor");
    af2.level = level;
    af2.duration = level/2;
    af2.location = APPLY_AC;
    af2.modifier = -20;
    af2.bitvector = 0;

    if (!is_affected( ch, af1.type ))
    {
	act("$n glows briefly.",ch,NULL,NULL,TO_ROOM);
	send_to_char("You glow briefly.\n\r", ch);
	affect_to_char(ch,&af1);
    }

    if (!is_affected( ch, af2.type ))
    {
	act("$n is suddenly surrounded by a glowing suit of armor.",ch,NULL,NULL,TO_ROOM);
	send_to_char("You are suddenly surrounded by a glowing suit of armor.\n\r", ch);
	affect_to_char(ch,&af2);
    }

    for ( vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room )
    {
	if (ch == vch)
	    continue;

	if (!IS_NPC(vch))
	{
	    if (number_percent() <= 80 && !is_affected( vch, af1.type ))
	    {
		act("$N glows briefly.",ch,NULL,vch,TO_ROOM);
		act("$N glows briefly.",ch,NULL,vch,TO_CHAR);
		send_to_char("You glow briefly.\n\r", vch);
		affect_to_char( vch, &af1 );
	    }
	    if (number_percent() <= 80 && !is_affected( vch, af2.type ))
	    {
		act("$N is suddenly surrounded by a glowing suit of armor.",ch,NULL,vch,TO_ROOM);
		act("$N is suddenly surrounded by a glowing suit of armor.",ch,NULL,vch,TO_CHAR);
		send_to_char("You are suddenly surrounded by a glowing suit of armor.\n\r", vch);
		affect_to_char( vch, &af2 );
	    }
	}
    }

    return;
}
