/***************************************************************************
* 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)
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;
}