dba/doc/
dba/doc/old/MPDocs/
dba/src/old_files/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik Strfeldt, 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                         *
 ***************************************************************************/

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

/*
 * Lookup a skill by name.
 */
int skill_lookup (const char *name)
{
    int sn;

    for (sn = 0; sn < MAX_SKILL; sn++)
    {
        if (skill_table[sn].name == NULL)
            break;
        if (LOWER (name[0]) == LOWER (skill_table[sn].name[0])
            && !str_prefix (name, skill_table[sn].name))
            return sn;
    }

    return -1;
}

/* skill_driver:
 * Does a skill. Checks for targets, shows messages, performs the skill.
 * Returns true if the character completes the skill.
 */
bool skill_driver (CHAR_DATA * ch, char *argument, int sn)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    void *vo;
    int target, sn_target;
    CHAR_DATA *victim;
    OBJ_DATA *obj;

	if (sn < 1)
		return FALSE;

    if (ch->position < skill_table[sn].minimum_position)
    {
        sendch ("You can't do that in your current position.\n\r", ch);
        return FALSE;
    }


	if (get_skill(ch, sn) < 1) {
		sendch ("What?\n\r", ch);
		return FALSE;
	}

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

    // Switch them if needed
    if (!str_cmp(arg1, "release")) {
        char t[MAX_INPUT_LENGTH];
        sprintf(t, arg2);
        sprintf(arg2, arg1);
        sprintf(arg1, t);
    }
    
    /*
     * Locate targets.
     */
    victim = NULL;
    obj = NULL;
    vo = NULL;
    target = TARGET_NONE;

	sn_target = skill_table[sn].target;
	// Look for skills whose targets switch at certain skill levels
	if (sn_target == TAR_HYBRID6) {
		if (get_skill(ch, sn) > 5 && !str_cmp(arg1, "all"))
			sn_target = TAR_AREA_OFF;
		else
			sn_target = TAR_CHAR_OFFENSIVE;
	}

    switch (sn_target)
    {
        default:
            logstr (LOG_BUG, "skill_driver: bad target for sn %d.", sn);
            return FALSE;

        case TAR_IGNORE:
        case TAR_AREA_OFF:
			vo = NULL;
			target = TARGET_NONE;
            break;

        case TAR_CHAR_OFFENSIVE:
            if (arg1[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    sendch ("Direct that at whom?\n\r", ch);
                    return FALSE;
                }
            }
            else
            {
                if ((victim = get_char_room (ch, NULL, arg1)) == NULL)
                {
                    sendch ("They aren't here.\n\r", ch);
                    return FALSE;
                }
            }

			if (ch == victim)
			{
				sendch( "You can't do that to yourself.\n\r", ch );
				return FALSE;
			}

            if (IS_NPC (victim) && victim->fighting != NULL && !is_same_group (ch, victim->fighting)) {
                sendch ("Kill stealing is not permitted.\n\r", ch);
                return FALSE;
            }

            if (!IS_NPC (ch))
            {

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

            if (IS_AFFECTED (ch, AFF_CHARM) && ch->master == victim)
            {
                sendch ("You can't do that on your own follower.\n\r", ch);
                return FALSE;
            }
		
            vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_DEFENSIVE:
            if (arg1[0] == '\0')
            {
                victim = ch;
            }
            else
            {
                if ((victim = get_char_room (ch, NULL, arg1)) == NULL)
                {
                    sendch ("They aren't here.\n\r", ch);
                    return FALSE;
                }
            }
			vo = (void *) victim;
            target = TARGET_CHAR;
            break;

        case TAR_CHAR_SELF:
            if (arg1[0] != '\0' && !is_name (arg1, ch->name))
            {
                sendch ("You cannot do that on another.\n\r", ch);
                return FALSE;
            }
			vo = (void *) ch;
            target = TARGET_CHAR;
            break;

        case TAR_OBJ_INV:
            if (arg1[0] == '\0')
            {
                sendch ("What object should that be done on?\n\r", ch);
                return FALSE;
            }

            if ((obj = get_obj_carry (ch, arg1, ch)) == NULL)
            {
                sendch ("You are not carrying that.\n\r", ch);
                return FALSE;
            }
			vo = (void *) obj;
            target = TARGET_OBJ;
            break;

        case TAR_OBJ_CHAR_OFF:
            if (arg1[0] == '\0')
            {
                if ((victim = ch->fighting) == NULL)
                {
                    sendch ("Do that on whom or what?\n\r", ch);
                    return FALSE;
                }

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

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

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

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

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

    if (ch->pl < 1)
    {
        sendch ("You're too exhausted.\n\r", ch);
        return FALSE;
    }

    // Use a ki_loss value based on the skill

    // Ki loss.
    // If its a charge type skill, make the initial loss much greater
    if (skill_table[sn].type == SKILL_CHARGE)
        ki_loss(ch, skill_table[sn].ki_mod*5);
    else
        ki_loss(ch, skill_table[sn].ki_mod);

    // Message if the skill is started
	if (skill_table[sn].msg_immediate1)
		act(skill_table[sn].msg_immediate1,ch,NULL,NULL,TO_CHAR);
	if (skill_table[sn].msg_immediate2)
		act(skill_table[sn].msg_immediate2,ch,NULL,NULL,TO_ROOM);


	// Make the char wait, and get the skill ready to fire (or fire it)
	if (skill_table[sn].type == SKILL_DELAY) {
		ch->wait_skill = skill_table[sn].wait;
		ch->wait_skill_sn = sn;
		ch->wait_skill_vo = vo;
		ch->wait_skill_target = target;
	}
	else if (skill_table[sn].type == SKILL_IMM) {
		wait (ch, skill_table[sn].wait);
		(*skill_table[sn].skill_fun) (ch, vo, target);
	}
    else if (skill_table[sn].type == SKILL_CHARGE) {
        ch->wait_skill = 0;
        ch->charge = 1;
        ch->wait_skill_sn = sn;
        ch->wait_skill_vo = vo;
        ch->wait_skill_target = target;
    }

    if ((sn_target == TAR_CHAR_OFFENSIVE
         || (sn_target == TAR_OBJ_CHAR_OFF
             && target == TARGET_CHAR))
	    && victim != ch
        && victim->master != ch
        && victim->fighting == NULL
        && IS_AWAKE(victim)
        && !IS_AFFECTED (victim, AFF_CALM) ) {
        check_killer (victim, ch);
        begin_combat (victim, ch);
    }
    else if (sn_target == TAR_AREA_OFF) {
		CHAR_DATA *vch;

        for (vch = ch->in_room->people; vch; vch = vch->next_in_room) {
            if (IS_NPC(vch)
                && vch->fighting == NULL
                && !IS_AFFECTED (vch, AFF_CALM)
                && !IS_AFFECTED (vch, AFF_CHARM)
                && IS_AWAKE (vch)
                && !IS_SET (vch->act, ACT_WIMPY)
                && !is_same_group(vch, ch)
                && can_see (vch, ch) ) {
                check_killer (vch, ch);
                begin_combat (vch, ch);
                break;
            }
        }
    }

    // Immediate "charged" attack
    if (skill_table[sn].type == SKILL_CHARGE &&
        (!str_cmp(arg1, "release") || !str_cmp(arg2, "release")) ) {
        // Pulled from do_release
        act("You release!",ch,NULL,NULL,TO_CHAR);
        act("$n releases!",ch,NULL,NULL,TO_ROOM);

        if (skill_table[ch->wait_skill_sn].msg_delay1)
            act(skill_table[ch->wait_skill_sn].msg_delay1,ch,NULL,NULL,TO_CHAR);
        if (skill_table[ch->wait_skill_sn].msg_delay2)
            act(skill_table[ch->wait_skill_sn].msg_delay2,ch,NULL,NULL,TO_ROOM);

        if (skill_table[ch->wait_skill_sn].skill_fun)
            (*skill_table[ch->wait_skill_sn].skill_fun) (ch, ch->wait_skill_vo, ch->wait_skill_target);

        ch->charge = 0;
        ch->wait_skill_sn = 0;
        ch->wait_skill_vo = NULL;
        ch->wait_skill_target = 0;
        wait (ch, 3 * PULSE_SECOND);
    }

    return TRUE;
}



/* used to get new skills */
void do_gain (CHAR_DATA * ch, char *argument)
{

    char buf[MAX_STRING_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *trainer;
    int sn = 0;

    return;

    if (IS_NPC (ch))
        return;

    /* find a trainer */
    for (trainer = ch->in_room->people;
         trainer != NULL; trainer = trainer->next_in_room)
        if (IS_NPC (trainer) && IS_SET (trainer->act, ACT_GAIN))
            break;

    if (trainer == NULL || !can_see (ch, trainer))
    {
        sendch ("You can't do that here.\n\r", ch);
        return;
    }

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
        do_function (trainer, &do_say, "Pardon me?");
        return;
    }

    if (!str_prefix (arg, "list"))
    {
        int col = 0;

        sprintf (buf, "%-18s %-5s %-18s %-5s %-18s %-5s\n\r",
                 "skill", "cost", "skill", "cost", "skill", "cost");
        sendch (buf, ch);

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

            if (!ch->pcdata->learned[sn]
                && skill_table[sn].points > 0)
            {
                sprintf (buf, "%-18s %-5d ",
                         skill_table[sn].name,
                         skill_table[sn].points);
                sendch (buf, ch);
                if (++col % 3 == 0)
                    sendch ("\n\r", ch);
            }
        }
        if (col % 3 != 0)
            sendch ("\n\r", ch);
        return;
    }

    /* else add a skill */
   
    sn = skill_lookup (argument);
    if (sn > -1) {
		bool found;
		int psn, i;

		// If the skill has no cost, it can't be learned
		if (skill_table[sn].points < 1)
			return;

        if (ch->pcdata->learned[sn]) {
            act ("$N tells you 'You already know that skill!'", ch, NULL, trainer, TO_CHAR);
            return;
        }

		found = FALSE;
		for (i=0; i<MAX_PC_RACE; ++i) {
			if (skill_table[sn].race_prereq[i] == NULL && i == 0) {
				// If no races needed for this skill, return that the race was found
				found = TRUE;
				break;
			}
			else
				break;

			if (race_lookup(skill_table[sn].race_prereq[i]) == ch->race) {
				found = TRUE;
				break;
			}
		}
		if (!found) {
			act ("$N tells you 'Those of $t origin may not learn this skill.'", ch, race_table[ch->race].name, trainer, TO_CHAR);
			return;
		}

		if (ch->pl < skill_table[sn].pl_prereq) {
			act ("$N tells you 'Your powerlevel is not yet high enough.'", ch, NULL, trainer, TO_CHAR);
			return;
		}

		for (i=0; i<5; ++i) {
			if (skill_table[sn].skill_prereq[i] == NULL)
				break;

			psn = skill_lookup(skill_table[sn].skill_prereq[i]);
			if (skill_table[sn].skill_value[i] > ch->pcdata->learned[psn]) {
				act ("$N tells you 'Your ability in $t is not yet great enough.'", ch, skill_table[psn].name, trainer, TO_CHAR);
				return;
			}
		}

		for (i=0; i<MAX_STATS; ++i) {
			if (ch->perm_stat[i] < skill_table[sn].stat_prereq[i]) {
				char buf[MAX_STRING_LENGTH];
				switch (i) {
					case STAT_STR: sprintf(buf, "strength"); break;
					case STAT_WIS: sprintf(buf, "wisdom"); break;
					case STAT_INT: sprintf(buf, "intelligence"); break;
					case STAT_DEX: sprintf(buf, "dexterity"); break;
					case STAT_CON: sprintf(buf, "constitution"); break;
					default:       sprintf(buf, "!error!"); break;
				}
				act ("$N tells you 'Your $t is too low to learn this skill.'", ch, buf, trainer, TO_CHAR);
				return;
			}
		}

        /* add the skill */
        ch->pcdata->learned[sn] = 1;
        act ("$N trains you in the art of $t.", ch, skill_table[sn].name, trainer, TO_CHAR);
        return;
    }

    act ("$N tells you 'I do not understand...'", ch, NULL, trainer, TO_CHAR);
}




/* RT spells and skills show the players spells (or skills) */
/*
void do_spells (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, ki;
    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))
            {
                sendch ("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);
                sendch (buf, ch);
                return;
            }

            if (argument[0] != '\0')
            {
                argument = one_argument (argument, arg);
                if (!is_number (arg))
                {
                    sendch ("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);
                    sendch (buf, ch);
                    return;
                }

                if (min_lev > max_lev)
                {
                    sendch ("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
            && 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
            {
                ki = UMAX (skill_table[sn].min_ki,
                             100 / (2 + ch->level - level));
                sprintf (buf, "%-18s  %3d ki  ", skill_table[sn].name,
                         ki);
            }

            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)
    {
        sendch ("No spells 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);
}
*/

void do_skills (CHAR_DATA * ch, char *argument)
{
    BUFFER *buffer;
    int sn;
    bool found=FALSE, bColumn1=TRUE;
    char buf[MAX_STRING_LENGTH];
	char buf_temp[MAX_STRING_LENGTH];

    if (IS_NPC (ch))
        return;

	sprintf(buf, "  ");

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

        if (ch->pcdata->learned[sn] > 0)
        {
            found = TRUE;
           
			sprintf (buf_temp, "%-20s %2d.%-2.2d          ", skill_table[sn].name, ch->pcdata->learned[sn],
				     100*ch->pcdata->skill_progress[sn]/(ch->pcdata->learned[sn]*15000));
			strcat (buf, buf_temp);

			if ((bColumn1=!bColumn1))
				strcat (buf, "\n\r  ");
        }
    }

    /* return results */

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

    buffer = new_buf ();
    add_buf (buffer, "Skills:\n\r");
	add_buf (buffer, buf);
    add_buf (buffer, "\n\r");
    page_to_char (buf_string (buffer), ch);
    free_buf (buffer);
}


/* checks for skill improvement */
void check_improve (CHAR_DATA * ch, int sn, bool success, int multiplier, long long int llVictimPl)
{
    //int gain;
	//int chance;
    char buf[100];
	int gain;

    if (IS_NPC (ch))
        return;

    if (sn <= 0 || sn >= MAX_SKILL //|| skill_table[sn].points == 0
        || ch->pcdata->learned[sn] <= 0 || ch->pcdata->learned[sn] >= 10)
        return;                    /* skill is not known, or cant be increased (at max) */

    gain = 2 * get_curr_stat (ch, STAT_INT) / multiplier;
	gain = UMIN(gain * 2, (((2 * llVictimPl * 100) / ch->pl) * gain) / 100);
	gain = ch->cur_pl * gain / 100;

	ch->pcdata->skill_progress[sn] += URANGE(1, gain, 100);

	if (ch->pcdata->skill_progress[sn] < ch->pcdata->learned[sn]*15000)
		return;

	if (success)
        sprintf (buf, "{CYou have become better at %s!{x\n\r", skill_table[sn].name);
    else
        sprintf (buf, "{CYou learn from your mistakes, and your %s improves!{x\n\r", skill_table[sn].name);
    sendch (buf, ch);
    ch->pcdata->learned[sn]++;
	ch->pcdata->skill_progress[sn] = 0;

    ch->train += UMAX(1, ch->pcdata->learned[sn] / 3);

    return;
}

/*
	if (wield != NULL)
		if (IS_WEAPON_STAT (wield, WEAPON_SHARP))
			dam += dam * 1 / 2;

	if (get_eq_char (ch, WEAR_SHIELD) == NULL)    // No shield = more
        dam = dam * 11 / 10;
	// Add some weapon bonus here:


	// Extra damage based on skills
	if (get_skill (ch, gsn_enhanced_damage) > 0)
    {
        // Extra enhanced damage
		if (number_percent() < 10 + get_skill (ch, gsn_enhanced_damage)*3) {
			check_improve (ch, gsn_enhanced_damage, TRUE, 5);
            dam *= UMAX(1, get_skill(ch, gsn_enhanced_damage)+1);
		}
		// Failed the check: normal damage
		else {
			check_improve (ch, gsn_enhanced_damage, TRUE, 6); // Worse chance to learn: didnt do a 'super' enchanced damage
            dam *= UMAX(1, (get_skill(ch, gsn_enhanced_damage)+1) / 2);
		}
    }
*/

// Returns a calculated value for chance to hit in melee based on powerlevel,
// stats, skill and other conditions, for some skill
long long int get_attackhit (CHAR_DATA *ch, int sn) {
    long long int value;

    value = get_curr_stat(ch, STAT_DEX);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 15;
    value *= UMAX(1,get_skill(ch, sn) / 2);
    value += GET_HITROLL(ch);

    if (sn == gsn_heart_shot)
        value /= 2;
    else if (sn == gsn_eye_gouge)
        value /= 10;

    if (ch->position < POS_FIGHTING)
        value /= 2;

    if (IS_AFFECTED (ch, AFF_BLIND))
        value -= value / 5;

    if (IS_AFFECTED (ch, AFF_FLYING))
        value += value / 4;

    if (ch->stance == STANCE_OFFEN)
        value += value / 4;
    else if (ch->stance == STANCE_DEFEN)
        value -= value / 4;
    else if (ch->stance == STANCE_KAMIK)
	value += value / 6;
// 	value = 3*value + (get_skill(ch, gsn_kamikaze)-1)*(value/4);
// 	3*value, +1 1/4 value per skill, after level 1

    value = value * (ch->balance+1) / 5;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}


long long int get_attackdam (CHAR_DATA *ch, int sn) {
    long long int value;

    value  = get_curr_stat(ch, STAT_STR);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 15;
    value *= UMAX(1,get_skill(ch, sn) / 2);
    value += GET_DAMROLL(ch);

    if (sn == gsn_throat_shot ||
        sn == gsn_sweep ||
        sn == gsn_eye_gouge)
        value = 1;
    else if (sn == gsn_knee)
        value /= 2;
    else if (sn == gsn_elbow)
        value /= 5;
    else if (sn == gsn_heart_shot)
        value *= 2;

    if (ch->position < POS_FIGHTING)
        value /= 2;

    value = UMAX(1, value);

    if (ch->stance == STANCE_OFFEN)
        value += value / 4;
    else if (ch->stance == STANCE_DEFEN)
        value -= value / 4;
    else if (ch->stance == STANCE_KAMIK)
        value = 4*value + (get_skill(ch, gsn_kamikaze)-1)*(value/4); 
	// 3*value, +1 1/4 value per skill, after level 1

    value = value * (ch->balance+1) / 5;
    value /= 2;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}

long long int get_attackabsorb (CHAR_DATA *ch, int sn, int dam_type) {
    long long int value;

    value  = get_curr_stat(ch, STAT_STR);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 50;
    value *= UMAX(1,get_skill(ch, sn) / 2);

    // Armor!
    switch (dam_type) {
        case DAM_NONE:                                  break;
        case DAM_PIERCE: value += ch->armor[AC_PIERCE] / 5; break;
        case DAM_BASH:   value += ch->armor[AC_BASH] / 5;   break;
        case DAM_SLASH:  value += ch->armor[AC_SLASH] / 5;  break;
        default:         value += ch->armor[AC_EXOTIC] / 5; break;
    }

    if (!IS_AWAKE (ch))
        value /= 4;
    else if (ch->position < POS_FIGHTING)
        value /= 2;

    if (ch->stance == STANCE_OFFEN)
        value -= value / 4;
    else if (ch->stance == STANCE_DEFEN)
        value += value / 4;
    else if (ch->stance == STANCE_KAMIK)
        value -= value / 2;

    if (IS_AFFECTED (ch, AFF_SANCTUARY))
        value *= 2;

    if ((IS_AFFECTED (ch, AFF_PROTECT_EVIL) && IS_EVIL (ch))
        || (IS_AFFECTED (ch, AFF_PROTECT_GOOD) && IS_GOOD (ch)))
        value += value / 4;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = value * (ch->balance+1) / 5;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}

long long int get_attackdodge (CHAR_DATA *ch, int sn) {
    long long int value;

    value  = get_curr_stat(ch, STAT_DEX);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 15;
    value *= UMAX(1,get_skill(ch, sn) / 2);

    if (!IS_AWAKE (ch))
        value /= 4;
    else if (ch->position < POS_FIGHTING)
        value /= 2;

    if (IS_AFFECTED (ch, AFF_BLIND))
        value -= value / 5;

    if (IS_AFFECTED (ch, AFF_FLYING))
        value += value / 4;

    if (ch->stance == STANCE_OFFEN)
        value -= value / 4;
    else if (ch->stance == STANCE_DEFEN)
        value += value / 4;
    else if (ch->stance == STANCE_KAMIK)
        value -= value / 2;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = value * (ch->balance+1) / 5;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}

long long int get_kihit (CHAR_DATA *ch, int sn) {
    long long int value;

    value  = get_curr_stat(ch, STAT_DEX);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 15;
    value *= UMAX(1,get_skill(ch, sn) / 2);
    value += GET_HITROLL(ch);

    if (ch->position < POS_FIGHTING)
        value /= 2;

    if (IS_AFFECTED (ch, AFF_BLIND))
        value -= value / 5;

    if (IS_AFFECTED (ch, AFF_FLYING))
        value += value / 4;

    if (sn == gsn_scattershot)
        value /= 2;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = value * (ch->balance+1) / 5;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}

long long int get_kidam (CHAR_DATA *ch, int sn) {
    long long int value;

    value  = (get_curr_stat(ch, STAT_INT) + get_curr_stat(ch,STAT_WIS)) / 2;
    value += sqrt(ch->cur_pl * ch->pl / 100) / 15;
    value *= UMAX(1,get_skill(ch, sn) / 2);

    if (sn == gsn_power_bomb)
        value *= 4;
    else if (sn == gsn_spirit_bomb || sn == gsn_death_ball)
        value *= 4;
    else if (sn == gsn_finalflash || sn == gsn_kamehameha || gsn_galic_gun)
        value *= 2;
    else if (sn == gsn_energy_ball)
        value /= 2;
    else if (sn == gsn_energy_beam)
        value /= 4;
    else if (sn == gsn_scattershot)
        value /= 5;

    if (ch->charge > 0)
        value = (ch->charge * value) / skill_table[sn].wait;
    if (ch->charge == 1) // Immediately released skill -- deduction
        value /= 4;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = value * (ch->balance+1) / 5;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}

long long int get_kiabsorb (CHAR_DATA *ch, int sn, int dam_type) {
    long long int value;

    value  = get_curr_stat(ch, STAT_STR);
    value += sqrt(ch->cur_pl * ch->pl / 100) / 50;
    value *= UMAX(1,get_skill(ch, sn) / 2);

    // Armor!
    switch (dam_type) {
        case DAM_NONE:                                  break;
        case DAM_PIERCE: value += ch->armor[AC_PIERCE] / 5; break;
        case DAM_BASH:   value += ch->armor[AC_BASH] / 5;   break;
        case DAM_SLASH:  value += ch->armor[AC_SLASH] / 5;  break;
        default:         value += ch->armor[AC_EXOTIC] / 5; break;
    }

    if (!IS_AWAKE (ch))
        value /= 4;
    else if (ch->position < POS_FIGHTING)
        value /= 2;

    if (ch->cur_pl < 1 && ch->ki < 1)
        value /= 50;

    value = value * (ch->balance+1) / 5;

    value = 2 * ch->cur_pl * value / 100;

    return value;
}