/* Code specifically for the new skill system */
#if defined(WIN32)
#include <time.h>
#else
#include <sys/time.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "merc.h"
#include "magic.h"
#include <math.h>
/* command procedures needed */
DECLARE_DO_FUN( do_groups );
DECLARE_DO_FUN( do_help );
DECLARE_DO_FUN( do_say );
DECLARE_DO_FUN( do_set );
extern bool has_racial_skill( CHAR_DATA * ch, long sn );
extern bool can_use( CHAR_DATA * ch, int sn );
void do_weapon( CHAR_DATA * ch, char *argument )
{
CHAR_DATA *victim;
OBJ_DATA *wield, *axe;
int chance, ch_weapon, vict_weapon;
if ( IS_NPC( ch ) )
return;
if ( ( victim = ch->fighting ) == NULL )
{
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if ( ( axe = get_eq_char( ch, WEAR_WIELD ) ) == NULL )
{
send_to_char( "You must be wielding a weapon.\n\r", ch );
return;
}
if ( ( chance = get_skill( ch, gsn_weapon_cleave ) ) == 0 )
{
send_to_char( "You don't know how to cleave opponents's weapon.\n\r",
ch );
return;
}
if ( ( wield = get_eq_char( victim, WEAR_WIELD ) ) == NULL )
{
send_to_char( "Your opponent must wield a weapon.\n\r", ch );
return;
}
/*
if ( check_material(wield,"platinum") || wield->pIndexData->limit != -1 )
return;*/
if ( axe->value[0] == WEAPON_AXE )
chance *= 1.2;
else if ( axe->value[0] != WEAPON_SWORD )
{
send_to_char( "Your weapon must be an axe or a sword.\n\r", ch );
return;
}
/* find weapon skills */
ch_weapon = get_weapon_skill( ch, get_weapon_sn( ch ) );
vict_weapon = get_weapon_skill( victim, get_weapon_sn( victim ) );
/* Stop up some divide by zero problems */
if ( IS_NPC( victim ) )
vict_weapon = victim->level * 12;
if ( vict_weapon <= 1 )
vict_weapon = 50;
/* modifiers */
/* skill */
chance = chance * ch_weapon / 200;
chance = chance * 100 / vict_weapon;
/* dex vs. strength */
chance += get_curr_stat( ch, STAT_DEX ) + get_curr_stat( ch, STAT_STR );
chance -= get_curr_stat( victim, STAT_STR ) +
2 * get_curr_stat( victim, STAT_DEX );
chance += ch->level - victim->level;
chance += axe->level - wield->level;
/* and now the attack */
/* SET_BIT(ch->affected_by,AFF_WEAK_STUN);*/
if ( number_percent( ) < chance )
{
WAIT_STATE( ch, skill_table[gsn_weapon_cleave].beats );
act( "You cleaved $N's weapon into two.", ch, NULL, victim, TO_CHAR );
act( "$n cleaved your weapon into two.", ch, NULL, victim, TO_VICT );
act( "$n cleaved $N's weapon into two.", ch, NULL, victim, TO_NOTVICT );
check_improve( ch, gsn_weapon_cleave, TRUE, 1 );
extract_obj( get_eq_char( victim, WEAR_WIELD ) );
}
else
{
WAIT_STATE( ch, skill_table[gsn_weapon_cleave].beats );
act( "You fail to cleave $N's weapon.", ch, NULL, victim, TO_CHAR );
act( "$n tries to cleave your weapon, but fails.", ch, NULL, victim,
TO_VICT );
act( "$n tries to cleave $N's weapon, but fails.", ch, NULL, victim,
TO_ROOM );
check_improve( ch, gsn_weapon_cleave, FALSE, 1 );
}
return;
}
void do_shield( CHAR_DATA * ch, char *argument )
{
CHAR_DATA *victim;
int chance, ch_weapon, vict_shield;
OBJ_DATA *shield, *axe;
if ( IS_NPC( ch ) )
return;
if ( ( victim = ch->fighting ) == NULL )
{
send_to_char( "You aren't fighting anyone.\n\r", ch );
return;
}
if ( ( axe = get_eq_char( ch, WEAR_WIELD ) ) == NULL )
{
send_to_char( "You must be wielding a weapon.\n\r", ch );
return;
}
if ( ( chance = get_skill( ch, gsn_shield_cleave ) ) == 0 )
{
send_to_char( "You don't know how to cleave opponents's shield.\n\r",
ch );
return;
}
if ( ( shield = get_eq_char( victim, WEAR_SHIELD ) ) == NULL )
{
send_to_char( "Your opponent must wield a shield.\n\r", ch );
return;
}
/* if ( check_material(shield,"platinum") || shield->pIndexData->limit
!= -1)
return;*/
if ( axe->value[0] == WEAPON_AXE )
chance *= 1.2;
else if ( axe->value[0] != WEAPON_SWORD )
{
send_to_char( "Your weapon must be an axe or a sword.\n\r", ch );
return;
}
/* find weapon skills */
ch_weapon = get_weapon_skill( ch, get_weapon_sn( ch ) );
vict_shield = get_skill( victim, gsn_shield_block );
if ( IS_NPC( victim ) )
vict_shield = victim->level * 10;
if ( vict_shield <= 1 )
vict_shield = 50;
/* modifiers */
/* skill */
chance = chance * ch_weapon / 200;
chance = chance * 100 / vict_shield;
/* dex vs. strength */
chance += get_curr_stat( ch, STAT_DEX );
chance -= 2 * get_curr_stat( victim, STAT_STR );
/* level */
/* chance += (ch->level - victim->level) * 2; */
chance += ch->level - victim->level;
chance += axe->level - shield->level;
/* and now the attack */
/* SET_BIT(ch->affected_by,AFF_WEAK_STUN);*/
if ( number_percent( ) < chance )
{
WAIT_STATE( ch, skill_table[gsn_shield_cleave].beats );
act( "You cleaved $N's shield into two.", ch, NULL, victim, TO_CHAR );
act( "$n cleaved your shield into two.", ch, NULL, victim, TO_VICT );
act( "$n cleaved $N's shield into two.", ch, NULL, victim, TO_NOTVICT );
check_improve( ch, gsn_shield_cleave, TRUE, 1 );
extract_obj( get_eq_char( victim, WEAR_SHIELD ) );
}
else
{
WAIT_STATE( ch, skill_table[gsn_shield_cleave].beats );
act( "You fail to cleave $N's shield.", ch, NULL, victim, TO_CHAR );
act( "$n tries to cleave your shield, but fails.", ch, NULL, victim,
TO_VICT );
act( "$n tries to cleave $N's shield, but fails.", ch, NULL, victim,
TO_ROOM );
check_improve( ch, gsn_shield_cleave, FALSE, 1 );
}
return;
}
int dgld_compare( const void *left, const void *right )
{
DO_GAIN_LIST_DATA *one = (DO_GAIN_LIST_DATA*)left;
DO_GAIN_LIST_DATA *two = (DO_GAIN_LIST_DATA*)right;
#ifdef WIN32
return stricmp( one->name, two->name );
#else
return strcasecmp( one->name, two->name );
#endif
}
/* used to get new skills */
void do_gain( CHAR_DATA * ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
CHAR_DATA *trainer;
int gn = 0, sn = 0;
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;
one_argument( argument, arg );
if ( arg[0] == '\0' )
{
if ( trainer == NULL || !can_see( ch, trainer ) )
send_to_char( "You can't do that here.\n\r", ch );
else
do_say( trainer, "Pardon me?" );
return;
}
buf[0] = '\0';
/* 'list' can now be used even when not in the presence of a trainer. -Zak */
if ( !str_prefix( arg, "list" ) )
{
DO_GAIN_LIST_DATA dgld_group[MAX_GROUP];
DO_GAIN_LIST_DATA dgld_skill[MAX_SKILL];
int dgld_group_count = 0;
int dgld_skill_count = 0;
/* Find groups that can be gained */
for ( gn = 0; gn<MAX_GROUP; gn++ )
{
/* Stop at the end */
if ( group_table[gn].name == NULL )
break;
if ( !ch->pcdata->group_known[gn]
&& group_table[gn].rating[ch->Class] > 0 )
{
dgld_group[dgld_group_count].name = group_table[gn].name;
dgld_group[dgld_group_count].level = 1; /* Level doesn't count for groups */
dgld_group[dgld_group_count].cost = group_table[gn].rating[ch->Class];
dgld_group_count++;
}
}
/* Display groups that can be gained */
if ( dgld_group_count > 0 )
{
int x;
strcat( buf, "`WSkill Group Cost Skill Group Cost`w\n\r" );
strcat( buf, "`K---------------------------------------------------------`w\n\r" );
qsort( dgld_group, dgld_group_count, sizeof(DO_GAIN_LIST_DATA), dgld_compare );
for ( x=0; x<dgld_group_count; x++ )
{
char buf2[MAX_STRING_LENGTH];
if ( x%2 == 0 )
sprintf( buf2, "%-18s %3d ", dgld_group[x].name, dgld_group[x].cost );
else
sprintf( buf2, "%-18s %3d\n\r", dgld_group[x].name, dgld_group[x].cost );
strcat( buf, buf2 );
}
if ( dgld_group_count%2 == 0 )
strcat( buf, "\n\r" );
else
strcat( buf, "\n\r\n\r" );
}
/* Find skills that can be gained */
for ( sn = 0; sn<MAX_SKILL; sn++ )
{
/* Stop at the end */
if ( skill_table[sn].name == NULL )
break;
if ( !ch->pcdata->learned[sn]
&& skill_table[sn].rating[ch->Class] > 0
&& skill_table[sn].spell_fun == spell_null )
{
dgld_skill[dgld_skill_count].name = skill_table[sn].name;
dgld_skill[dgld_skill_count].cost = skill_table[sn].rating[ch->Class];
dgld_skill[dgld_skill_count].level = skill_table[sn].skill_level[ch->Class];
dgld_skill_count++;
}
}
/* Display skills that can be gained */
if ( dgld_skill_count > 0 )
{
int x;
strcat( buf, "`WSkill Level Cost Skill Level Cost`w\n\r" );
strcat( buf, "`K---------------------------------------------------------`w\n\r" );
qsort( dgld_skill, dgld_skill_count, sizeof(DO_GAIN_LIST_DATA), dgld_compare );
for ( x=0; x<dgld_skill_count; x++ )
{
char buf2[MAX_STRING_LENGTH];
if ( x%2 == 0 )
sprintf( buf2, "%-18s %3d %3d ", dgld_skill[x].name, dgld_skill[x].level, dgld_skill[x].cost );
else
sprintf( buf2, "%-18s %3d %3d\n\r", dgld_skill[x].name, dgld_skill[x].level, dgld_skill[x].cost );
strcat( buf, buf2 );
}
if ( dgld_skill_count%2 == 0 )
strcat( buf, "\n\r" );
else
strcat( buf, "\n\r\n\r" );
}
page_to_char( buf, ch );
return;
}
if ( trainer == NULL || !can_see( ch, trainer ) )
{
send_to_char( "You can't do that here.\n\r", ch );
return;
}
#ifdef CAN_GAIN_CONVERT
if ( !str_prefix( arg, "convert" ) )
{
if ( ch->practice < 10 )
{
act( "$N tells you 'You are not yet ready.'",
ch, NULL, trainer, TO_CHAR );
return;
}
act( "$N helps you apply your practice to training",
ch, NULL, trainer, TO_CHAR );
ch->practice -= 10;
ch->train += 1;
return;
}
#endif
#ifdef CAN_GAIN_REVERT
if ( !str_prefix( arg, "revert" ) )
{
if ( ch->train < 1 )
{
act( "$N tells you 'You are not yet ready.'",
ch, NULL, trainer, TO_CHAR );
return;
}
act( "$N helps you apply your training to practice.",
ch, NULL, trainer, TO_CHAR );
ch->train -= 1;
ch->practice += 8;
return;
}
#endif
if ( !str_prefix( arg, "points" ) )
{
if ( ch->train < 2 )
{
act( "$N tells you 'You are not yet ready.'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( ch->pcdata->points <= CP_TRAIN_MIN )
{
act( "$N tells you 'There would be no point in that.'",
ch, NULL, trainer, TO_CHAR );
return;
}
act( "$N trains you, and you feel more at ease with your skills.",
ch, NULL, trainer, TO_CHAR );
ch->train -= 2;
ch->pcdata->points -= 1;
ch->exp = 0;
return;
}
/* else add a group/skill */
gn = group_lookup( argument );
if ( gn > 0 )
{
if ( ch->pcdata->group_known[gn] )
{
act( "$N tells you 'You already know that group!'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( group_table[gn].rating[ch->Class] <= 0 )
{
act( "$N tells you 'That group is beyond your powers.'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( ch->train < group_table[gn].rating[ch->Class] )
{
act( "$N tells you 'You are not yet ready for that group.'",
ch, NULL, trainer, TO_CHAR );
return;
}
/* add the group */
gn_add( ch, gn );
act( "$N trains you in the art of $t",
ch, group_table[gn].name, trainer, TO_CHAR );
ch->train -= group_table[gn].rating[ch->Class];
return;
}
sn = skill_lookup( argument );
if ( sn > -1 )
{
if ( skill_table[sn].spell_fun != spell_null )
{
act( "$N tells you 'You must learn the full group.'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( ch->pcdata->learned[sn] )
{
act( "$N tells you 'You already know that skill!'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( skill_table[sn].rating[ch->Class] <= 0 )
{
act( "$N tells you 'That skill is beyond your powers.'",
ch, NULL, trainer, TO_CHAR );
return;
}
if ( ch->train < skill_table[sn].rating[ch->Class] )
{
act( "$N tells you 'You are not yet ready for that skill.'",
ch, NULL, 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 );
ch->train -= skill_table[sn].rating[ch->Class];
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_splist( CHAR_DATA * ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char buf3[MAX_STRING_LENGTH];
char spell_list[LEVEL_HERO][MAX_STRING_LENGTH];
char spell_columns[LEVEL_HERO];
int sn, lev;
int oldclass;
bool found = FALSE;
int x;
if ( IS_NPC( ch ) )
return;
if ( argument == NULL )
{
send_to_char( "Syntax:\n\r "
" slist <class>\n\r\n\rWhere class is one of:\n\r", ch );
for ( x = 0; x < MAX_CLASS; x++ )
{
printf_to_char( ch, " %s\n\r", class_table[x].who_name );
}
send_to_char( "\n\r", ch );
return;
}
for ( x = 0; x < MAX_CLASS; x++ )
{
if ( !str_cmp( argument, class_table[x].who_name ) )
break;
}
if ( x >= MAX_CLASS )
{
printf_to_char( ch,
"No class named '%s' exists.\n\rClass should be one of:\n\r",
argument );
for ( x = 0; x < MAX_CLASS; x++ )
{
printf_to_char( ch, " %s\n\r", class_table[x].who_name );
}
send_to_char( "\n\r", ch );
return;
}
oldclass = ch->Class;
sprintf( buf3, "char self class %s", argument );
do_set( ch, buf3 );
/* initilize data */
for ( lev = 0; lev < LEVEL_HERO; lev++ )
{
spell_columns[lev] = 0;
spell_list[lev][0] = '\0';
}
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( skill_table[sn].skill_level[ch->Class] < LEVEL_HERO &&
skill_table[sn].spell_fun != spell_null &&
ch->pcdata->learned[sn] > 0 )
{
found = TRUE;
lev = skill_table[sn].skill_level[ch->Class];
{
sprintf( buf, "%-18s %3d ", skill_table[sn].name,
skill_table[sn].rating[ch->Class] );
}
if ( spell_list[lev][0] == '\0' )
sprintf( spell_list[lev], "\n\rLevel %2d: %s", lev, buf );
else /* append */
{
if ( ++spell_columns[lev] % 2 == 0 )
strcat( spell_list[lev], "\n\r " );
strcat( spell_list[lev], buf );
}
}
}
/* return results */
if ( !found )
{
send_to_char( "This class has no spells.\n\r", ch );
ch->Class = oldclass;
return;
}
for ( lev = 0; lev < LEVEL_HERO; lev++ )
if ( spell_list[lev][0] != '\0' )
send_to_char( spell_list[lev], ch );
send_to_char( "\n\r", ch );
ch->Class = oldclass;
}
void do_spells( CHAR_DATA * ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char spell_list[LEVEL_HERO][MAX_STRING_LENGTH];
char spell_columns[LEVEL_HERO];
int sn, lev, mana;
bool found = FALSE;
if ( IS_NPC( ch ) )
return;
/* initilize data */
for ( lev = 0; lev < LEVEL_HERO; lev++ )
{
spell_columns[lev] = 0;
spell_list[lev][0] = '\0';
}
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( skill_table[sn].skill_level[ch->Class] < LEVEL_HERO &&
skill_table[sn].spell_fun != spell_null &&
ch->pcdata->learned[sn] > 0 )
{
found = TRUE;
lev = skill_table[sn].skill_level[ch->Class];
if ( ch->level < lev )
sprintf( buf, "%-18s n/a ", skill_table[sn].name );
else
{
mana = UMAX( skill_table[sn].min_mana,
100 / ( 2 + ch->level - lev ) );
sprintf( buf, "%-18s %3d mana ", skill_table[sn].name, mana );
}
if ( spell_list[lev][0] == '\0' )
sprintf( spell_list[lev], "\n\rLevel %2d: %s", lev, buf );
else /* append */
{
if ( ++spell_columns[lev] % 2 == 0 )
strcat( spell_list[lev], "\n\r " );
strcat( spell_list[lev], buf );
}
}
}
/* return results */
if ( !found )
{
send_to_char( "You know no spells.\n\r", ch );
return;
}
for ( lev = 0; lev < LEVEL_HERO; lev++ )
if ( spell_list[lev][0] != '\0' )
send_to_char( spell_list[lev], ch );
send_to_char( "\n\r", ch );
}
int dsd_compare_name( const void* left, const void* right )
{
DO_SKILLS_DATA *one = (DO_SKILLS_DATA*)left;
DO_SKILLS_DATA *two = (DO_SKILLS_DATA*)right;
#ifdef WIN32
return stricmp( one->name, two->name );
#else
return strcasecmp( one->name, two->name );
#endif
}
int dsd_compare_lvl_name( const void* left, const void* right )
{
DO_SKILLS_DATA *one = (DO_SKILLS_DATA*)left;
DO_SKILLS_DATA *two = (DO_SKILLS_DATA*)right;
if ( one->level < two->level )
return -1;
else if ( one->level > two->level )
return 1;
else
return dsd_compare_name( left, right );
}
void do_skills( CHAR_DATA * ch, char *argument )
{
DO_SKILLS_DATA dsd_racial[5];
DO_SKILLS_DATA dsd_learned[MAX_SKILL];
DO_SKILLS_DATA dsd_unlearned[MAX_SKILL];
int dsd_racial_count = 0;
int dsd_learned_count = 0;
int dsd_unlearned_count = 0;
int sn;
char buf[4*MAX_STRING_LENGTH];
/* TODO: static sized string buffers suck - Ember needs a dynamicly sized string buffer.
* Maybe we'll switch to C++ and can use std::string? <shrug> -Zak */
if ( IS_NPC( ch ) )
{
send_to_char( "NPCs have access to all skills", ch );
return;
}
buf[0] = '\0';
/* Loop through all skills */
for ( sn = 0; sn<MAX_SKILL; sn++ )
{
/* Stop at the end */
if ( skill_table[sn].name == NULL )
break;
/* Skip over spells */
if ( skill_table[sn].spell_fun != spell_null )
continue;
/* racial skills */
if ( has_racial_skill( ch, sn ) )
{
dsd_racial[dsd_racial_count].name = skill_table[sn].name;
dsd_racial[dsd_racial_count].level = 1; /* Racial skills are always level 1 */
dsd_racial[dsd_racial_count].learned = ch->pcdata->learned[sn];
dsd_racial_count++;
}
/* learned skills */
else if ( ch->level >= skill_table[sn].skill_level[ch->Class] && ch->pcdata->learned[sn] > 0 )
{
dsd_learned[dsd_learned_count].name = skill_table[sn].name;
dsd_learned[dsd_learned_count].level = skill_table[sn].skill_level[ch->Class];
dsd_learned[dsd_learned_count].learned = ch->pcdata->learned[sn];
dsd_learned_count++;
}
/* unlearned skills */
else if ( ch->pcdata->learned[sn] > 0 )
{
dsd_unlearned[dsd_unlearned_count].name = skill_table[sn].name;
dsd_unlearned[dsd_unlearned_count].level = skill_table[sn].skill_level[ch->Class];
dsd_unlearned[dsd_unlearned_count].learned = ch->pcdata->learned[sn];
dsd_unlearned_count++;
}
}
if ( dsd_racial_count > 0 )
{
int x;
strcat( buf, "`wInnate Abilities\n\r`K----------------`w\n\r" );
qsort( dsd_racial, dsd_racial_count, sizeof(DO_SKILLS_DATA), dsd_compare_name );
for ( x=0; x<dsd_racial_count; x++ )
{
char buf2[MAX_STRING_LENGTH];
if ( x%2 == 0 )
sprintf( buf2, "`w%-18s `W%3d%% ", dsd_racial[x].name, dsd_racial[x].learned );
else
sprintf( buf2, "`w%-18s `W%3d%%`w\n\r", dsd_racial[x].name, dsd_racial[x].learned );
strcat( buf, buf2 );
}
if ( dsd_racial_count%2 == 0 )
strcat( buf, "\n\r" );
else
strcat( buf, "\n\r\n\r" );
}
if ( dsd_learned_count > 0 )
{
int x;
strcat( buf, "`wLearned Skills\n\r`K----------------`w\n\r" );
qsort( dsd_learned, dsd_learned_count, sizeof(DO_SKILLS_DATA), dsd_compare_name );
for ( x=0; x<dsd_learned_count; x++ )
{
char buf2[MAX_STRING_LENGTH];
if ( x%2 == 0 )
sprintf( buf2, "`w%-18s `W%3d%% ", dsd_learned[x].name, dsd_learned[x].learned );
else
sprintf( buf2, "`w%-18s `W%3d%%`w\n\r", dsd_learned[x].name, dsd_learned[x].learned );
strcat( buf, buf2 );
}
if ( dsd_learned_count%2 == 0 )
strcat( buf, "\n\r" );
else
strcat( buf, "\n\r\n\r" );
}
if ( dsd_unlearned_count > 0 )
{
int x;
strcat( buf, "`wUnlearned Skills\n\r`K----------------`w\n\r" );
qsort( dsd_unlearned, dsd_unlearned_count, sizeof(DO_SKILLS_DATA), dsd_compare_lvl_name );
for ( x=0; x<dsd_unlearned_count; x++ )
{
char buf2[MAX_STRING_LENGTH];
if ( x%2 == 0 )
sprintf( buf2, "`w%-18s `K[`WLevel %3d`K] ", dsd_unlearned[x].name, dsd_unlearned[x].level );
else
sprintf( buf2, "`w%-18s `K[`WLevel %3d`K]`w\n\r", dsd_unlearned[x].name, dsd_unlearned[x].level );
strcat( buf, buf2 );
}
if ( dsd_unlearned_count%2 == 0 )
strcat( buf, "\n\r" );
else
strcat( buf, "\n\r\n\r" );
}
page_to_char( buf, ch );
}
void do_sklist( CHAR_DATA * ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
char buf3[MAX_STRING_LENGTH];
char skill_list[LEVEL_HERO][MAX_STRING_LENGTH];
char skill_columns[LEVEL_HERO];
int sn, lev, x, oldclass;
bool found = FALSE;
oldclass = 0;
if ( IS_NPC( ch ) )
return;
if ( argument == NULL )
{
send_to_char( "Syntax:\n\r "
" slist <class>\n\r\n\rWhere class is one of:\n\r", ch );
for ( x = 0; x < MAX_CLASS; x++ )
{
printf_to_char( ch, " %s\n\r", class_table[x].who_name );
}
send_to_char( "\n\r", ch );
return;
}
for ( x = 0; x < MAX_CLASS; x++ )
{
if ( !str_cmp( argument, class_table[x].who_name ) )
break;
}
if ( x >= MAX_CLASS )
{
printf_to_char( ch,
"No class named '%s' exists.\n\rClass should be one of:\n\r",
argument );
for ( x = 0; x < MAX_CLASS; x++ )
{
printf_to_char( ch, " %s\n\r", class_table[x].who_name );
}
send_to_char( "\n\r", ch );
return;
}
oldclass = ch->Class;
sprintf( buf3, "char self class %s", argument );
do_set( ch, buf3 );
/* initilize data */
for ( lev = 0; lev < LEVEL_HERO; lev++ )
{
skill_columns[lev] = 0;
skill_list[lev][0] = '\0';
}
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( skill_table[sn].skill_level[ch->Class] < LEVEL_HERO &&
skill_table[sn].spell_fun == spell_null )
{
found = TRUE;
lev = skill_table[sn].skill_level[ch->Class];
sprintf( buf, "%-18s %3d ", skill_table[sn].name,
skill_table[sn].rating[ch->Class] );
if ( skill_list[lev][0] == '\0' )
sprintf( skill_list[lev], "\n\rLevel %2d: %s", lev, buf );
else /* append */
{
if ( ++skill_columns[lev] % 2 == 0 )
strcat( skill_list[lev], "\n\r " );
strcat( skill_list[lev], buf );
}
}
}
/* return results */
if ( !found )
{
send_to_char( "You know no skills.\n\r", ch );
ch->Class = oldclass;
return;
}
for ( lev = 0; lev < LEVEL_HERO; lev++ )
if ( skill_list[lev][0] != '\0' )
send_to_char( skill_list[lev], ch );
send_to_char( "\n\r", ch );
ch->Class = oldclass;
}
/* shows skills, groups and costs (only if not bought) */
void list_group_costs( CHAR_DATA * ch )
{
char buf[MAX_STRING_LENGTH];
int gn, sn, col;
if ( IS_NPC( ch ) )
return;
col = 0;
sprintf( buf, "%-18s %-5s %-18s %-5s %-18s %-5s\n\r", "group", "cp",
"group", "cp", "group", "cp" );
send_to_char( buf, ch );
for ( gn = 0; gn < MAX_GROUP; gn++ )
{
if ( group_table[gn].name == NULL )
break;
if ( !ch->gen_data->group_chosen[gn]
&& !ch->pcdata->group_known[gn]
&& group_table[gn].rating[ch->Class] > 0 )
{
sprintf( buf, "%-18s %-5d ", group_table[gn].name,
group_table[gn].rating[ch->Class] );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
send_to_char( "\n\r", ch );
col = 0;
sprintf( buf, "%-18s %-5s %-18s %-5s %-18s %-5s\n\r", "skill", "cp",
"skill", "cp", "skill", "cp" );
send_to_char( buf, ch );
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( !ch->gen_data->skill_chosen[sn]
&& ch->pcdata->learned[sn] == 0
&& skill_table[sn].spell_fun == spell_null
&& skill_table[sn].rating[ch->Class] > 0 )
{
sprintf( buf, "%-18s %-5d ", skill_table[sn].name,
skill_table[sn].rating[ch->Class] );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
send_to_char( "\n\r", ch );
sprintf( buf, "Creation points: %d\n\r", ch->pcdata->points );
send_to_char( buf, ch );
sprintf( buf,
"Experience modifier: %d%% (Percent of difference from the norm)\n\r",
figure_difference( ch->gen_data->points_chosen ) );
send_to_char( buf, ch );
return;
}
void list_group_chosen( CHAR_DATA * ch )
{
char buf[MAX_STRING_LENGTH];
int gn, sn, col;
if ( IS_NPC( ch ) )
return;
col = 0;
sprintf( buf, "%-18s %-5s %-18s %-5s %-18s %-5s", "group", "cp", "group",
"cp", "group", "cp\n\r" );
send_to_char( buf, ch );
for ( gn = 0; gn < MAX_GROUP; gn++ )
{
if ( group_table[gn].name == NULL )
break;
if ( ch->gen_data->group_chosen[gn]
&& group_table[gn].rating[ch->Class] > 0 )
{
sprintf( buf, "%-18s %-5d ", group_table[gn].name,
group_table[gn].rating[ch->Class] );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
send_to_char( "\n\r", ch );
col = 0;
sprintf( buf, "%-18s %-5s %-18s %-5s %-18s %-5s", "skill", "cp", "skill",
"cp", "skill", "cp\n\r" );
send_to_char( buf, ch );
for ( sn = 0; sn < MAX_SKILL; sn++ )
{
if ( skill_table[sn].name == NULL )
break;
if ( ch->gen_data->skill_chosen[sn]
&& skill_table[sn].rating[ch->Class] > 0 )
{
sprintf( buf, "%-18s %-5d ", skill_table[sn].name,
skill_table[sn].rating[ch->Class] );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
send_to_char( "\n\r", ch );
sprintf( buf, "Creation points: %d\n\r", ch->gen_data->points_chosen );
send_to_char( buf, ch );
sprintf( buf,
"Experience modifier: %d%% (Percent of difference from the norm)\n\r",
figure_difference( ch->gen_data->points_chosen ) );
send_to_char( buf, ch );
return;
}
long exp_per_level( CHAR_DATA * ch, int points )
{
long expl = 0;
if ( IS_NPC( ch ) )
return 1000;
switch ( ch->level )
{
case 1:
expl = 750;
break;
case 2:
expl = 1500;
break;
case 3:
expl = 3000;
break;
case 4:
expl = 6000;
break;
case 5:
expl = 12000;
break;
case 6:
expl = 24000;
break;
case 7:
expl = 48000;
break;
case 8:
expl = 96000;
break;
case 9:
expl = 192000;
break;
case 10:
expl = 384000;
break;
case 11:
expl = 768000;
break;
case 12:
expl = 1536000;
break;
case 13:
expl = 1996800;
break;
case 14:
expl = 2595840;
break;
case 15:
expl = 3374590;
break;
case 16:
expl = 4386970;
break;
case 17:
expl = 5703060;
break;
case 18:
expl = 7413970;
break;
case 19:
expl = 9638170;
break;
case 20:
expl = 12529620;
break;
case 21:
expl = 16288510;
break;
case 22:
expl = 19546214;
break;
case 23:
expl = 23455450;
break;
case 24:
expl = 28146540;
break;
case 25:
expl = 33775850;
break;
case 26:
expl = 37153440;
break;
case 27:
expl = 40868780;
break;
case 28:
expl = 44955660;
break;
case 29:
expl = 49451230;
break;
case 30:
expl = 53523100;
break;
case 31:
expl = 57500000;
break;
case 32:
expl = 61506090;
break;
case 33:
expl = 65571300;
break;
case 34:
expl = 69696969;
break;
case 35:
expl = 74530130;
break;
case 36:
expl = 79590170;
break;
case 37:
expl = 84567800;
break;
case 38:
expl = 89012000;
break;
case 39:
expl = 94500600;
break;
case 40:
expl = 99503030;
break;
case 41:
expl = 104000000;
break;
case 42:
expl = 108000000;
break;
case 43:
expl = 112000000;
break;
case 44:
expl = 116000000;
break;
case 45:
expl = 120000000;
break;
case 46:
expl = 124000000;
break;
case 47:
expl = 128000000;
break;
case 48:
expl = 132000000;
break;
case 49:
expl = 136000000;
break;
case 50:
expl = 140000000;
break;
case 51:
expl = 150000000;
break;
case 52:
expl = 160000000;
break;
case 53:
expl = 170000000;
break;
case 54:
expl = 180000000;
break;
case 55:
expl = 190000000;
break;
case 56:
expl = 200000000;
break;
case 57:
expl = 210000000;
break;
case 58:
expl = 220000000;
break;
case 59:
expl = 230000000;
break;
case 60:
expl = 240000000;
break;
case 61:
expl = 250000000;
break;
case 62:
expl = 260000000;
break;
case 63:
expl = 270000000;
break;
case 64:
expl = 280000000;
break;
case 65:
expl = 290000000;
break;
case 66:
expl = 300000000;
break;
case 67:
expl = 310000000;
break;
case 68:
expl = 320000000;
break;
case 69:
expl = 330000000;
break;
case 70:
expl = 340000000;
break;
case 71:
expl = 350000000;
break;
case 72:
expl = 360000000;
break;
case 73:
expl = 370000000;
break;
case 74:
expl = 380000000;
break;
case 75:
expl = 390000000;
break;
case 76:
expl = 400000000;
break;
case 77:
expl = 410000000;
break;
case 78:
expl = 420000000;
break;
case 79:
expl = 430000000;
break;
case 80:
expl = 460000000;
break;
case 81:
expl = 480000000;
break;
case 82:
expl = 500000000;
break;
case 83:
expl = 520000000;
break;
case 84:
expl = 540000000;
break;
case 85:
expl = 560000000;
break;
case 86:
expl = 580000000;
break;
case 87:
expl = 600000000;
break;
case 88:
expl = 620000000;
break;
case 89:
expl = 640000000;
break;
case 90:
expl = 660000000;
break;
case 91:
expl = 700000000;
break;
case 92:
expl = 999999999;
break;
case 93:
expl = 999999999;
break;
case 94:
expl = 999999999;
break;
case 95:
expl = 999999999;
break;
case 96:
expl = 999999999;
break;
case 97:
expl = 999999999;
break;
case 98:
expl = 999999999;
break;
case 99:
expl = 999999999;
break;
case 100:
expl = 999999999;
break;
}
/* if (points > 110) expl=(long)pow((double)110,(double)1.2)*(expl/100); */
if ( points <= CP_MIN_PENALTY )
points += CP_PENALTY;
if ( points >= 28 )
expl =
( long ) pow( ( double ) points, ( double ) 1.2 ) * ( expl / 100 );
/* && (points <= 110)) */
if ( points < 28 )
expl = ( long ) ( expl * ( ( 26.0 + points ) / 100.0 ) );
/* if (points < 40)
return 1000 * pc_race_table[ch->race].class_mult[ch->Class]/100;
/ processing /
points -= 40;
while (points > 9)
{
expl += inc;
points -= 10;
if (points > 9)
{
expl += inc;
inc *= 2;
points -= 10;
}
}
expl += points * inc / 10;*/
return expl * ( pc_race_table[ch->race].class_mult[ch->Class] / 100 );
}
/* this procedure handles the input parsing for the skill generator */
bool parse_gen_groups( CHAR_DATA * ch, char *argument )
{
char arg[MAX_INPUT_LENGTH];
char buf[MAX_STRING_LENGTH];
int gn, sn, i;
if ( argument[0] == '\0' )
return FALSE;
argument = one_argument( argument, arg );
if ( !str_prefix( arg, "help" ) )
{
if ( argument[0] == '\0' )
{
do_help( ch, "group help" );
return TRUE;
}
do_help( ch, argument );
return TRUE;
}
if ( !str_prefix( arg, "add" ) )
{
if ( argument[0] == '\0' )
{
send_to_char( "You must provide a skill name.\n\r", ch );
return TRUE;
}
/* Fix this to look for groups that person already has and only charge for the ones they don't. -Zane */
gn = group_lookup( argument );
if ( gn != -1 )
{
if ( ch->gen_data->group_chosen[gn] || ch->pcdata->group_known[gn] )
{
send_to_char( "You already know that group!\n\r", ch );
return TRUE;
}
if ( group_table[gn].rating[ch->Class] < 1 )
{
send_to_char( "That group is not available.\n\r", ch );
return TRUE;
}
/* If this is broken, please mail dennis@realms.reichel.net :-) */
for ( i = 0; group_table[gn].spells[i] != NULL; i++ )
{
if ( group_lookup( group_table[gn].spells[i] ) == -1 )
continue;
if ( ch->pcdata->
group_known[group_lookup( group_table[gn].spells[i] )] )
{
send_to_char
( "That group contains groups you already know.\n\r",
ch );
send_to_char
( "Please \"drop\" them if you wish to gain this one.\n\r",
ch );
return TRUE;
}
}
for ( i = 0; group_table[gn].spells[i] != NULL; i++ )
{
if ( skill_lookup( group_table[gn].spells[i] ) == -1 )
continue;
if ( ch->gen_data->
skill_chosen[skill_lookup( group_table[gn].spells[i] )] )
{
send_to_char
( "That group contains skills/spells you already know.\n\r",
ch );
send_to_char
( "Please \"drop\" them if you wish to gain this one.\n\r",
ch );
return TRUE;
}
}
sprintf( buf, "%s group added\n\r", group_table[gn].name );
send_to_char( buf, ch );
ch->gen_data->group_chosen[gn] = TRUE;
ch->gen_data->points_chosen += group_table[gn].rating[ch->Class];
gn_add( ch, gn );
ch->pcdata->points += group_table[gn].rating[ch->Class];
return TRUE;
}
sn = skill_lookup( argument );
if ( sn != -1 )
{
if ( ch->gen_data->skill_chosen[sn] || ch->pcdata->learned[sn] > 0 )
{
send_to_char( "You already know that skill!\n\r", ch );
return TRUE;
}
if ( skill_table[sn].rating[ch->Class] < 1
|| skill_table[sn].spell_fun != spell_null )
{
send_to_char( "That skill is not available.\n\r", ch );
return TRUE;
}
sprintf( buf, "%s skill added\n\r", skill_table[sn].name );
send_to_char( buf, ch );
ch->gen_data->skill_chosen[sn] = TRUE;
ch->gen_data->points_chosen += skill_table[sn].rating[ch->Class];
ch->pcdata->learned[sn] = 1;
ch->pcdata->points += skill_table[sn].rating[ch->Class];
return TRUE;
}
send_to_char( "No skills or groups by that name...\n\r", ch );
return TRUE;
}
if ( !strcmp( arg, "drop" ) )
{
if ( argument[0] == '\0' )
{
send_to_char( "You must provide a skill to drop.\n\r", ch );
return TRUE;
}
gn = group_lookup( argument );
if ( gn != -1 && ch->gen_data->group_chosen[gn] )
{
send_to_char( "Group dropped.\n\r", ch );
ch->gen_data->group_chosen[gn] = FALSE;
ch->gen_data->points_chosen -= group_table[gn].rating[ch->Class];
gn_remove( ch, gn );
for ( i = 0; i < MAX_GROUP; i++ )
{
if ( ch->gen_data->group_chosen[gn] )
gn_add( ch, gn );
}
ch->pcdata->points -= group_table[gn].rating[ch->Class];
return TRUE;
}
sn = skill_lookup( argument );
if ( sn != -1 && ch->gen_data->skill_chosen[sn] )
{
send_to_char( "Skill dropped.\n\r", ch );
ch->gen_data->skill_chosen[sn] = FALSE;
ch->gen_data->points_chosen -= skill_table[sn].rating[ch->Class];
ch->pcdata->learned[sn] = 0;
ch->pcdata->points -= skill_table[sn].rating[ch->Class];
return TRUE;
}
send_to_char( "You haven't bought any such skill or group.\n\r", ch );
return TRUE;
}
if ( !str_prefix( arg, "premise" ) )
{
do_help( ch, "premise" );
return TRUE;
}
if ( !str_prefix( arg, "list" ) )
{
list_group_costs( ch );
return TRUE;
}
if ( !str_prefix( arg, "learned" ) )
{
list_group_chosen( ch );
return TRUE;
}
if ( !str_prefix( arg, "info" ) )
{
do_groups( ch, argument );
return TRUE;
}
return FALSE;
}
/* shows all groups, or the sub-members of a group */
void do_groups( CHAR_DATA * ch, char *argument )
{
char buf[MAX_STRING_LENGTH];
int gn, sn, col;
if ( IS_NPC( ch ) )
return;
col = 0;
if ( argument[0] == '\0' )
{ /* show all groups */
for ( gn = 0; gn < MAX_GROUP; gn++ )
{
if ( group_table[gn].name == NULL )
break;
if ( ch->pcdata->group_known[gn] )
{
sprintf( buf, "%-20s ", group_table[gn].name );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
sprintf( buf, "Creation points: %d\n\r", ch->pcdata->points );
send_to_char( buf, ch );
return;
}
if ( !str_cmp( argument, "all" ) ) /* show all groups */
{
for ( gn = 0; gn < MAX_GROUP; gn++ )
{
if ( group_table[gn].name == NULL )
break;
sprintf( buf, "%-20s ", group_table[gn].name );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
return;
}
/* show the sub-members of a group */
gn = group_lookup( argument );
if ( gn == -1 )
{
send_to_char( "No group of that name exist.\n\r", ch );
send_to_char( "Type 'groups all' or 'info all' for a full listing.\n\r",
ch );
return;
}
for ( sn = 0; sn < MAX_IN_GROUP; sn++ )
{
if ( group_table[gn].spells[sn] == NULL )
break;
sprintf( buf, "%-20s ", group_table[gn].spells[sn] );
send_to_char( buf, ch );
if ( ++col % 3 == 0 )
send_to_char( "\n\r", ch );
}
if ( col % 3 != 0 )
send_to_char( "\n\r", ch );
}
/* checks for skill improvement */
void check_improve( CHAR_DATA * ch, int sn, bool success, int multiplier )
{
char buf[MAX_STRING_LENGTH];
int chance;
if ( IS_NPC( ch ) )
return;
if ( ch->level < skill_table[sn].skill_level[ch->Class]
|| skill_table[sn].rating[ch->Class] == 0
|| ch->pcdata->learned[sn] == 0 || ch->pcdata->learned[sn] == 100 )
return; /* skill is not known */
/* check to see if the character has a chance to learn */
chance = 10 * int_app[get_curr_stat( ch, STAT_INT )].learn;
chance /= ( multiplier * skill_table[sn].rating[ch->Class] * 4 );
chance += ch->level;
if ( number_range( 1, 1000 ) > chance )
return;
/* now that the character has a CHANCE to learn, see if they really have */
#ifdef SKILL_DEBUG
printf_to_char( ch, "checking on %s's skills", ch->name );
#endif
if ( success )
{
chance = URANGE( 5, 100 - ch->pcdata->learned[sn], 95 );
if ( number_percent( ) < chance )
{
sprintf( buf, "You have become better at %s!\n\r",
skill_table[sn].name );
send_to_char( buf, ch );
ch->pcdata->learned[sn]++;
gain_exp( ch, 2 * skill_table[sn].rating[ch->Class] );
}
}
else
{
chance = URANGE( 5, ch->pcdata->learned[sn] / 2, 30 );
if ( number_percent( ) < chance )
{
sprintf( buf,
"You learn from your mistakes, and your %s skill improves.\n\r",
skill_table[sn].name );
send_to_char( buf, ch );
ch->pcdata->learned[sn] += number_range( 1, 3 );
ch->pcdata->learned[sn] = UMIN( ch->pcdata->learned[sn], 100 );
gain_exp( ch, 2 * skill_table[sn].rating[ch->Class] );
}
}
}
/* returns a group index number given the name */
int group_lookup( const char *name )
{
int gn;
for ( gn = 0; gn < MAX_GROUP; gn++ )
{
if ( group_table[gn].name == NULL )
break;
if ( LOWER( name[0] ) == LOWER( group_table[gn].name[0] )
&& !str_prefix( name, group_table[gn].name ) )
return gn;
}
return -1;
}
/* recursively adds a group given its number -- uses group_add */
void gn_add( CHAR_DATA * ch, int gn )
{
int i;
ch->pcdata->group_known[gn] = TRUE;
for ( i = 0; i < MAX_IN_GROUP; i++ )
{
if ( group_table[gn].spells[i] == NULL )
break;
group_add( ch, group_table[gn].spells[i], FALSE );
}
}
/* recusively removes a group given its number -- uses group_remove */
void gn_remove( CHAR_DATA * ch, int gn )
{
int i;
ch->pcdata->group_known[gn] = FALSE;
for ( i = 0; i < MAX_IN_GROUP; i++ )
{
if ( group_table[gn].spells[i] == NULL )
break;
group_remove( ch, group_table[gn].spells[i] );
}
}
/* use for processing a skill or group for addition */
void group_add( CHAR_DATA * ch, const char *name, bool deduct )
{
int sn, gn;
if ( IS_NPC( ch ) ) /* NPCs do not have skills */
return;
sn = skill_lookup( name );
if ( sn != -1 )
{
if ( ch->pcdata->learned[sn] == 0 ) /* i.e. not known */
{
ch->pcdata->learned[sn] = 1;
if ( deduct )
ch->pcdata->points += skill_table[sn].rating[ch->Class];
}
return;
}
/* now check groups */
gn = group_lookup( name );
if ( gn != -1 )
{
if ( ch->pcdata->group_known[gn] == FALSE )
{
ch->pcdata->group_known[gn] = TRUE;
if ( deduct )
ch->pcdata->points += group_table[gn].rating[ch->Class];
}
gn_add( ch, gn ); /* make sure all skills in the group are known */
}
}
/* used for processing a skill or group for deletion -- no points back! */
void group_remove( CHAR_DATA * ch, const char *name )
{
int sn, gn;
sn = skill_lookup( name );
if ( sn != -1 )
{
ch->pcdata->learned[sn] = 0;
return;
}
/* now check groups */
gn = group_lookup( name );
if ( gn != -1 && ch->pcdata->group_known[gn] == TRUE )
{
ch->pcdata->group_known[gn] = FALSE;
gn_remove( ch, gn ); /* be sure to call gn_add on all remaining groups */
}
}