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