/*Bard Special Stuff -- Work in Progress
  Josh - 2/1/02*/
#include "include.h"
#include "interp.h"
#include "bard.h"
#include "recycle.h"

char *target_name;
bool isSung;

void do_play_instrument (CHAR_DATA * ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    void *vo;
    int mana;
    int sn;
    int target;

	OBJ_DATA *instrument;
	isSung = FALSE;

    /*
     * Switched NPC's can play songs, but others can't.
     */
    if (IS_NPC (ch) && ch->desc == NULL)
        return;

	if (ch->class != MAX_CLASS && !(IS_IMMORTAL(ch)))
	{
		send_to_char("You couldn't play an instrument if your life depended on it.\n\r", ch);
		return;
	}

    target_name = one_argument (argument, arg1);
    one_argument (target_name, arg2);

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

	if ((instrument = get_eq_char (ch, WEAR_HOLD)) == NULL)
    {
        send_to_char ("You hold nothing in your hand.\n\r", ch);
        return;
    }

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

    if ((sn = find_spell (ch, arg1)) < 1
		|| skill_table[sn].slot != 999
        || skill_table[sn].spell_fun == spell_null || (!IS_NPC (ch)
        && (ch->level < skill_table[sn].skill_level[ch->class]
        || ch->pcdata->learned[sn] == 0)))
    {
        send_to_char ("You don't know any songs of that name.\n\r", ch);
        return;
    }

    if (ch->position < skill_table[sn].minimum_position)
    {
        send_to_char ("You can't concentrate enough.\n\r", ch);
        return;
    }

    if (ch->level + 2 == skill_table[sn].skill_level[ch->class])
        mana = 50;
    else
        mana = UMAX (skill_table[sn].min_mana,
                     100 / (2 + ch->level -
                            skill_table[sn].skill_level[ch->class]));

    /*
     * Locate targets.
     */
    victim = NULL;
    obj = NULL;
    vo = NULL;
    target = TARGET_NONE;

    switch (skill_table[sn].target)
    {
        default:
            bug ("Do_play: bad target for sn %d.", sn);
            return;

        case TAR_IGNORE:
            break;

        case TAR_CHAR_OFFENSIVE:
            if (arg2[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    send_to_char ("Play the song to whom?\n\r", ch);
                    return;
                }
            }
            else
            {
                if ((victim = get_char_room (ch, target_name)) == NULL)
                {
                    send_to_char ("They aren't here.\n\r", ch);
                    return;
                }
            }
/*
        if ( ch == victim )
        {
            send_to_char( "You can't do that to yourself.\n\r", ch );
            return;
        }
*/


            if (!IS_NPC (ch))
            {

                if (is_safe (ch, victim) && victim != ch)
                {
                    send_to_char ("Not on that target.\n\r", ch);
                    return;
                }
                check_killer (ch, victim);
            }

            if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
            {
                send_to_char ("You can't do that on your own follower.\n\r",
                              ch);
                return;
            }

            vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_DEFENSIVE:
            if (arg2[0] == '\0')
            {
                victim = ch;
            }
            else
            {
                if ((victim = get_char_room (ch, target_name)) == NULL)
                {
                    send_to_char ("They aren't here.\n\r", ch);
                    return;
                }
            }

            vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_SELF:
            if (arg2[0] != '\0' && !is_name (target_name, ch->name))
            {
                send_to_char ("You cannot play this song to another.\n\r",
                              ch);
                return;
            }

            vo = (void *) ch;
            target = TARGET_CHAR;
            break;

        case TAR_OBJ_INV:
            if (arg2[0] == '\0')
            {
                send_to_char ("What should the song be bound to?\n\r", ch);
                return;
            }

            if ((obj = get_obj_carry (ch, target_name, ch)) == NULL)
            {
                send_to_char ("You are not carrying that.\n\r", ch);
                return;
            }

            vo = (void *) obj;
            target = TARGET_OBJ;
            break;

        case TAR_OBJ_CHAR_OFF:
            if (arg2[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    send_to_char ("Play the song to whom or what?\n\r", ch);
                    return;
                }

                target = TARGET_CHAR;
            }
            else if ((victim = get_char_room (ch, target_name)) != NULL)
            {
                target = TARGET_CHAR;
            }

            if (target == TARGET_CHAR)
            {                    /* check the sanity of the attack */
                if (is_safe_spell (ch, victim, FALSE) && victim != ch)
                {
                    send_to_char ("Not on that target.\n\r", ch);
                    return;
                }

                if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
                {
                    send_to_char
                        ("You can't do that on your own follower.\n\r", ch);
                    return;
                }

                if (!IS_NPC (ch))
                    check_killer (ch, victim);

                vo = (void *) victim;
            }
            else if ((obj = get_obj_here (ch, target_name)) != NULL)
            {
                vo = (void *) obj;
                target = TARGET_OBJ;
            }
            else
            {
                send_to_char ("You don't see that here.\n\r", ch);
                return;
            }
            break;

        case TAR_OBJ_CHAR_DEF:
            if (arg2[0] == '\0')
            {
                vo = (void *) ch;
                target = TARGET_CHAR;
            }
            else if ((victim = get_char_room (ch, target_name)) != NULL)
            {
                vo = (void *) victim;
                target = TARGET_CHAR;
            }
            else if ((obj = get_obj_carry (ch, target_name, ch)) != NULL)
            {
                vo = (void *) obj;
                target = TARGET_OBJ;
            }
            else
            {
                send_to_char ("You don't see that here.\n\r", ch);
                return;
            }
            break;
    }

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


    WAIT_STATE (ch, skill_table[sn].beats);

    if (number_percent () > get_skill (ch, sn))
    {
        send_to_char ("You fumbled a note.\n\r", ch);
        check_improve (ch, sn, FALSE, 1);
        ch->mana -= mana / 2;
    }
    else
    {
        ch->mana -= mana;
        if (IS_NPC (ch) || class_table[ch->class].fMana)
            /* class has spells */
            (*skill_table[sn].spell_fun) (sn, ch->level, ch, vo, target);
        else
            (*skill_table[sn].spell_fun) (sn, 3 * ch->level / 4, ch, vo, target);
        check_improve (ch, sn, TRUE, 1);
    }

    if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE
         || (skill_table[sn].target == TAR_OBJ_CHAR_OFF
             && target == TARGET_CHAR)) && victim != ch
        && victim->master != ch)
    {
        CHAR_DATA *vch;
        CHAR_DATA *vch_next;

        for (vch = ch->in_room->people; vch; vch = vch_next)
        {
            vch_next = vch->next_in_room;
            if (victim == vch && victim->fighting == NULL)
            {
                check_killer (victim, ch);
                multi_hit (victim, ch, TYPE_UNDEFINED);
                break;
            }
        }
    }

    return;
}

void do_sing (CHAR_DATA * ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;
    OBJ_DATA *obj;
    void *vo;
    int mana;
    int sn;
    int target;

	isSung = TRUE;


    /*
     * Switched NPC's can sing songs, but others can't.
     */
    if (IS_NPC (ch) && ch->desc == NULL)
        return;

	if (ch->class != MAX_CLASS && !(IS_IMMORTAL(ch)))
	{
		send_to_char("You couldn't sing if your life depended on it.\n\r", ch);
		return;
	}

    target_name = one_argument (argument, arg1);
    one_argument (target_name, arg2);

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


    if ((sn = find_spell (ch, arg1)) < 1
		|| skill_table[sn].slot != 999
        || skill_table[sn].spell_fun == spell_null || (!IS_NPC (ch)
        && (ch->level < skill_table[sn].skill_level[ch->class]
        || ch->pcdata->learned[sn] == 0)))
    {
        send_to_char ("You don't know any songs of that name.\n\r", ch);
        return;
    }

    if (ch->position < skill_table[sn].minimum_position)
    {
        send_to_char ("You can't concentrate enough.\n\r", ch);
        return;
    }

    if (ch->level + 2 == skill_table[sn].skill_level[ch->class])
        mana = 50;
    else
        mana = UMAX (skill_table[sn].min_mana,
                     100 / (2 + ch->level -
                            skill_table[sn].skill_level[ch->class]));

    /*
     * Locate targets.
     */
    victim = NULL;
    obj = NULL;
    vo = NULL;
    target = TARGET_NONE;

    switch (skill_table[sn].target)
    {
        default:
            bug ("Do_play: bad target for sn %d.", sn);
            return;

        case TAR_IGNORE:
            break;

        case TAR_CHAR_OFFENSIVE:
            if (arg2[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    send_to_char ("Sing the song to whom?\n\r", ch);
                    return;
                }
            }
            else
            {
                if ((victim = get_char_room (ch, target_name)) == NULL)
                {
                    send_to_char ("They aren't here.\n\r", ch);
                    return;
                }
            }
/*
        if ( ch == victim )
        {
            send_to_char( "You can't do that to yourself.\n\r", ch );
            return;
        }
*/


            if (!IS_NPC (ch))
            {

                if (is_safe (ch, victim) && victim != ch)
                {
                    send_to_char ("Not on that target.\n\r", ch);
                    return;
                }
                check_killer (ch, victim);
            }

            if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
            {
                send_to_char ("You can't do that on your own follower.\n\r",
                              ch);
                return;
            }

            vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_DEFENSIVE:
            if (arg2[0] == '\0')
            {
                victim = ch;
            }
            else
            {
                if ((victim = get_char_room (ch, target_name)) == NULL)
                {
                    send_to_char ("They aren't here.\n\r", ch);
                    return;
                }
            }

            vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_SELF:
            if (arg2[0] != '\0' && !is_name (target_name, ch->name))
            {
                send_to_char ("You cannot sing this song to another.\n\r",
                              ch);
                return;
            }

            vo = (void *) ch;
            target = TARGET_CHAR;
            break;

        case TAR_OBJ_INV:
            if (arg2[0] == '\0')
            {
                send_to_char ("What should the song be bound to?\n\r", ch);
                return;
            }

            if ((obj = get_obj_carry (ch, target_name, ch)) == NULL)
            {
                send_to_char ("You are not carrying that.\n\r", ch);
                return;
            }

            vo = (void *) obj;
            target = TARGET_OBJ;
            break;

        case TAR_OBJ_CHAR_OFF:
            if (arg2[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    send_to_char ("Sing the song to whom or what?\n\r", ch);
                    return;
                }

                target = TARGET_CHAR;
            }
            else if ((victim = get_char_room (ch, target_name)) != NULL)
            {
                target = TARGET_CHAR;
            }

            if (target == TARGET_CHAR)
            {                    /* check the sanity of the attack */
                if (is_safe_spell (ch, victim, FALSE) && victim != ch)
                {
                    send_to_char ("Not on that target.\n\r", ch);
                    return;
                }

                if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
                {
                    send_to_char
                        ("You can't do that on your own follower.\n\r", ch);
                    return;
                }

                if (!IS_NPC (ch))
                    check_killer (ch, victim);

                vo = (void *) victim;
            }
            else if ((obj = get_obj_here (ch, target_name)) != NULL)
            {
                vo = (void *) obj;
                target = TARGET_OBJ;
            }
            else
            {
                send_to_char ("You don't see that here.\n\r", ch);
                return;
            }
            break;

        case TAR_OBJ_CHAR_DEF:
            if (arg2[0] == '\0')
            {
                vo = (void *) ch;
                target = TARGET_CHAR;
            }
            else if ((victim = get_char_room (ch, target_name)) != NULL)
            {
                vo = (void *) victim;
                target = TARGET_CHAR;
            }
            else if ((obj = get_obj_carry (ch, target_name, ch)) != NULL)
            {
                vo = (void *) obj;
                target = TARGET_OBJ;
            }
            else
            {
                send_to_char ("You don't see that here.\n\r", ch);
                return;
            }
            break;
    }

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


    WAIT_STATE (ch, skill_table[sn].beats);

    if (number_percent () > get_skill (ch, sn))
    {
        send_to_char ("You sang off key.\n\r", ch);
        check_improve (ch, sn, FALSE, 1);
        ch->mana -= mana / 2;
    }
    else
    {
        ch->mana -= mana;
        if (IS_NPC (ch) || class_table[ch->class].fMana)
            /* class has spells */
            (*skill_table[sn].spell_fun) (sn, ch->level, ch, vo, target);
        else
            (*skill_table[sn].spell_fun) (sn, 3 * ch->level / 4, ch, vo, target);
        check_improve (ch, sn, TRUE, 1);
    }

    if ((skill_table[sn].target == TAR_CHAR_OFFENSIVE
         || (skill_table[sn].target == TAR_OBJ_CHAR_OFF
             && target == TARGET_CHAR)) && victim != ch
        && victim->master != ch)
    {
        CHAR_DATA *vch;
        CHAR_DATA *vch_next;

        for (vch = ch->in_room->people; vch; vch = vch_next)
        {
            vch_next = vch->next_in_room;
            if (victim == vch && victim->fighting == NULL)
            {
                check_killer (victim, ch);
                multi_hit (victim, ch, TYPE_UNDEFINED);
                break;
            }
        }
    }

    return;
}

/*Song Lookup*/
void do_songs (CHAR_DATA * ch, char *argument)
{
    BUFFER *buffer;
    char arg[MAX_INPUT_LENGTH];
    char spell_list[LEVEL_HERO + 1][MAX_STRING_LENGTH];
    char spell_columns[LEVEL_HERO + 1];
    int sn, level, min_lev = 1, max_lev = LEVEL_HERO, mana;
    bool fAll = FALSE, found = FALSE;
    char buf[MAX_STRING_LENGTH];

    if (IS_NPC (ch))
        return;

    if (argument[0] != '\0')
    {
        fAll = TRUE;

        if (str_prefix (argument, "all"))
        {
            argument = one_argument (argument, arg);
            if (!is_number (arg))
            {
                send_to_char ("Arguments must be numerical or all.\n\r", ch);
                return;
            }
            max_lev = atoi (arg);

            if (max_lev < 1 || max_lev > LEVEL_HERO)
            {
                sprintf (buf, "Levels must be between 1 and %d.\n\r",
                         LEVEL_HERO);
                send_to_char (buf, ch);
                return;
            }

            if (argument[0] != '\0')
            {
                argument = one_argument (argument, arg);
                if (!is_number (arg))
                {
                    send_to_char ("Arguments must be numerical or all.\n\r",
                                  ch);
                    return;
                }
                min_lev = max_lev;
                max_lev = atoi (arg);

                if (max_lev < 1 || max_lev > LEVEL_HERO)
                {
                    sprintf (buf,
                             "Levels must be between 1 and %d.\n\r",
                             LEVEL_HERO);
                    send_to_char (buf, ch);
                    return;
                }

                if (min_lev > max_lev)
                {
                    send_to_char ("That would be silly.\n\r", ch);
                    return;
                }
            }
        }
    }


    /* initialize data */
    for (level = 0; level < LEVEL_HERO + 1; level++)
    {
        spell_columns[level] = 0;
        spell_list[level][0] = '\0';
    }

    for (sn = 0; sn < MAX_SKILL; sn++)
    {
        if (skill_table[sn].name == NULL)
            break;

        if ((level = skill_table[sn].skill_level[ch->class]) < LEVEL_HERO + 1
            && (fAll || level <= ch->level)
            && level >= min_lev && level <= max_lev
            && skill_table[sn].spell_fun != spell_null
			&& skill_table[sn].slot == 999
            && ch->pcdata->learned[sn] > 0)
        {
            found = TRUE;
            level = skill_table[sn].skill_level[ch->class];
            if (ch->level < level)
                sprintf (buf, "%-18s n/a      ", skill_table[sn].name);
            else
            {
                mana = UMAX (skill_table[sn].min_mana,
                             100 / (2 + ch->level - level));
                sprintf (buf, "%-18s  %3d mana  ", skill_table[sn].name,
                         mana);
            }

            if (spell_list[level][0] == '\0')
                sprintf (spell_list[level], "\n\rLevel %2d: %s", level, buf);
            else
            {                    /* append */

                if (++spell_columns[level] % 2 == 0)
                    strcat (spell_list[level], "\n\r          ");
                strcat (spell_list[level], buf);
            }
        }
    }

    /* return results */

    if (!found)
    {
        send_to_char ("No songs found.\n\r", ch);
        return;
    }

    buffer = new_buf ();
    for (level = 0; level < LEVEL_HERO + 1; level++)
        if (spell_list[level][0] != '\0')
            add_buf (buffer, spell_list[level]);
    add_buf (buffer, "\n\r");
    page_to_char (buf_string (buffer), ch);
    free_buf (buffer);
}

/*Start
	Songs*/

void song_test(int sn, int level, CHAR_DATA * ch, void *vo,
                        int target)
{
	OBJ_DATA *instrument;
	instrument = get_eq_char (ch, WEAR_HOLD);

	if(isSung)
	{
		act("You sing the test song.", ch, instrument, NULL, TO_CHAR);
		act("$n sings the test song.", ch, instrument, NULL, TO_ROOM);
	}
	else
	{
		act("You play the test song on $p.", ch, instrument, NULL, TO_CHAR);
		act("$n plays the test song on $p.", ch, instrument, NULL, TO_ROOM);
	}
	return;
}