/**************************************************************************/ // skills.cpp - gain, train, prac etc /*************************************************************************** * The Dawn of Time v1.69r (c)1997-2004 Michael Garratt * * >> A number of people have contributed to the Dawn codebase, with the * * majority of code written by Michael Garratt - www.dawnoftime.org * * >> To use this source code, you must fully comply with all the licenses * * in licenses.txt... In particular, you may not remove this copyright * * notice. * *************************************************************************** * >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer, * * Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe. * * >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael * * Chastain, Michael Quan, and Mitchell Tse. * * >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to * * you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com), * * Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) * * >> Oblivion 1.2 is copyright 1996 Wes Wagner * **************************************************************************/ #include "include.h" // dawn standard includes #include "magic.h" #include "d2magsys.h" #include "math.h" #include "nanny.h" // command procedures needed DECLARE_DO_FUN(do_skillgroups); DECLARE_DO_FUN(do_help ); DECLARE_DO_FUN(do_say ); DECLARE_DO_FUN(do_spinfo ); DECLARE_DO_FUN(do_cspinfo ); DECLARE_DO_FUN(do_cskinfo ); /**************************************************************************/ // used to get new skills void do_gain(char_data *ch, char *argument) { char arg[MIL]; char_data *trainer; int gn = 0, sn = 0; if (IS_NPC(ch)) return; // find a trainer for ( trainer = ch->in_room->people; trainer; trainer = trainer->next_in_room) { if (IS_NPC(trainer) && IS_SET(trainer->act,ACT_GAIN)) break; } if (trainer == NULL || !can_see(ch,trainer)) { ch->println( "You can't do that here." ); return; } one_argument(argument,arg); if (arg[0] == '\0') { do_say(trainer,"Pardon me?"); return; } if (!str_prefix(arg,"list")) { int col; col = 0; ch->printlnf("%-28s %-5s %-28s %-5s", "skillgroup","cost","skillgroup","cost"); // groups up below for (gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++) { if (!ch->pcdata->skillgroup_known[gn] && IS_SKILLGROUP_SELECTABLE_FOR_CHAR(gn, ch)) { ch->printf("%s%-28s %-5d ", skillgroup_table[gn].rating[ch->clss]>ch->train?"`S":"`x", skillgroup_table[gn].name, skillgroup_table[gn].rating[ch->clss]); if (++col % 2 == 0){ ch->print_blank_lines(1); } } } if (col % 2 != 0) { ch->println(""); } // skillgroups up above ch->println("`x"); // skills below col = 0; ch->print("`?`#`Yskill `^==============" "`Ycost`^==`Ylevel`^======="); ch->println("`Yskill`^==============`Ycost" "`^==`Ylevel`x"); for (sn = 0; sn < MAX_SKILL; sn++) { if (IS_NULLSTR(skill_table[sn].name)){ break; } if(IS_SET(skill_table[sn].flags,SKFLAGS_NO_GAIN)){ continue; } if( IS_SET(skill_table[sn].flags,SKFLAGS_USE_RACE_RESTRICTIONS) && !IS_SETn(skill_table[sn].race_restrict_n, ch->race)) { continue; } if (!ch->pcdata->learned[sn] && skill_table[sn].rating[ch->clss] > 0 && skill_table[sn].skill_level[ch->clss]< LEVEL_IMMORTAL && skill_table[sn].skill_level[ch->clss]>0 && skill_table[sn].spell_fun == spell_null) { ch->printf("%s%-18s %3d %4d ", skill_table[sn].rating[ch->clss]>ch->train?"`S":"`x", skill_table[sn].name, skill_table[sn].rating[ch->clss], skill_table[sn].skill_level[ch->clss]); if (++col % 2 == 0) ch->print_blank_lines(1); } } if (col % 2 != 0){ ch->println("`x"); }else{ ch->print("`x"); } return; // skills above }// gain list if ( ch->position < POS_STANDING ) { ch->println( "You need to stand first." ); return; } 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++; return; } if (!str_prefix(arg,"revert")) { if (ch->train < 1) { act("$N tells you 'You are not yet ready.'", ch,NULL,trainer,TO_CHAR); return; } if(ch->level<10) { ch->println("You can't revert trains before level 10."); return; } act("$N helps you apply your practice to training", ch,NULL,trainer,TO_CHAR); ch->practice+=10; ch->train--; return; } 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 <= 40) { 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); // record how much xp they have beyond their current level int beyond=UMAX(0, ch->exp - (exp_per_level(ch,ch->pcdata->points) * ch->level)); // reduce their creation points ch->train -= 2; ch->pcdata->points -= 1; ch->exp = exp_per_level(ch,ch->pcdata->points) * ch->level; // give them back the xp they already had on that given level if(beyond){ gain_exp(ch, beyond); } return; } /* else add a group/skill */ gn = skillgroup_lookup(argument); if (gn > 0) { if (ch->pcdata->skillgroup_known[gn]) { act("$N tells you 'You already know that skillgroup!'", ch,NULL,trainer,TO_CHAR); return; } if (skillgroup_table[gn].rating[ch->clss] <= 0) { act("$N tells you 'That skillgroup is beyond your powers.'", ch,NULL,trainer,TO_CHAR); return; } if (ch->train < skillgroup_table[gn].rating[ch->clss]) { act("$N tells you 'You are not yet ready for that skillgroup.'", ch,NULL,trainer,TO_CHAR); return; } if (!IS_SKILLGROUP_SELECTABLE_FOR_CHAR(gn, ch)){ ch->printlnf("%s tells you 'You aren't ready for the skillgroup '%s' at this point in time.'", PERS(trainer, ch), skillgroup_table[gn].name); return; } // add the group gn_add(ch,gn); act("$N trains you in the art of $t", ch,skillgroup_table[gn].name,trainer,TO_CHAR); ch->train -= skillgroup_table[gn].rating[ch->clss]; set_char_magic_bits(ch); // fix up their magic bits return; } sn = skill_lookup(argument); if (sn > -1) { if (skill_table[sn].spell_fun && skill_table[sn].spell_fun != spell_null) { act("$N tells you 'You must learn the full group.'", ch,NULL,trainer,TO_CHAR); return; } if( IS_SET(skill_table[sn].flags,SKFLAGS_USE_RACE_RESTRICTIONS) && !IS_SETn(skill_table[sn].race_restrict_n, ch->race)) { act("$N tells you 'Your race can't learn that skill.'", ch,NULL,trainer,TO_CHAR); return; } if(IS_SET(skill_table[sn].flags,SKFLAGS_NO_GAIN)){ act("$N tells you 'That skill can't be gained sorry.'", 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->clss] <= 0 || skill_table[sn].skill_level[ch->clss] >= LEVEL_IMMORTAL || skill_table[sn].skill_level[ch->clss]<=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->clss]*1) { 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->clss]*1; set_char_magic_bits(ch); // fix up their magic bits return; } act("$N tells you 'I do not understand...'",ch,NULL,trainer,TO_CHAR); } /**************************************************************************/ char * creation_titlebar(char *fmt, ...); /**************************************************************************/ void do_skills(char_data *ch, char *argument) { char *skill_list[MAX_LEVEL+2]; unsigned char skill_columns[MAX_LEVEL+2]; char linebuf[MSL]; int sn,lev; char arg[MIL]; char_data *victim; char buf[MSL]; BUFFER *output; int top_level=0; bool found = false; if (IS_UNSWITCHED_MOB(ch)){ return; } one_argument( argument, arg ); if (IS_IMMORTAL(ch) && !IS_NULLSTR(arg)) { if ( ( victim = get_char_world( ch, arg ) ) == NULL ) { ch->println( "They aren't here." ); return; } } else { victim=ch; } if (IS_NPC(victim)) { ch->println( "Mobs dont have skill percentages as such." ); return; } output = new_buf(); { if(ch->desc && ch->desc->connected_state!=CON_PLAYING){ if(ch==victim){ sprintf(buf,"`=j%s", creation_titlebar("SKILLS")); }else{ sprintf(buf,"`=j%s", creation_titlebar("SKILLS FOR %s", uppercase(victim->name))); } }else{ if(ch==victim){ sprintf(buf,"`=t%s", makef_titlebar("SKILLS")); }else{ sprintf(buf,"`=t%s", makef_titlebar("SKILLS FOR %s", uppercase(victim->name))); } } buf[str_len(buf)-2]= '\0'; strcat(buf,"`x"); } add_buf( output, buf); if (ch!=victim) { sprintf(buf,"\r\nSkills for %s (Level: %d, Race: %s, Class: %s)", victim->name, victim->level, race_table[victim->race]->name, class_table[victim->clss].name); add_buf( output, buf); } // initialize data for (lev = 0; lev < MAX_LEVEL+2; lev++){ skill_columns[lev] = 0; skill_list[lev]= str_dup(""); } if (IS_IMMORTAL(ch)){ top_level= ABSOLUTE_MAX_LEVEL; }else{ top_level= LEVEL_HERO; } bool specially_granted_skills=false; for (sn = 0; !IS_NULLSTR(skill_table[sn].name) ; sn++) { if (skill_table[sn].spell_fun == spell_null && ( (victim->pcdata->learned[sn]==101) || (skill_table[sn].skill_level[victim->clss]<=top_level && skill_table[sn].skill_level[victim->clss]>0 && victim->pcdata->learned[sn] > 0) ) ) { if(victim->pcdata->learned[sn]==101 && skill_table[sn].skill_level[victim->clss]>LEVEL_HERO) { specially_granted_skills=true; } found = true; lev = skill_table[sn].skill_level[victim->clss]; if(IS_SET(skill_table[sn].flags,SKFLAGS_NEW_IMPROVE_SYSTEM)){ if (victim->level < lev){ sprintf(buf,"%-18s n/a ", capitalize(skill_table[sn].name)); }else{ sprintf(buf,"%-18s %3d%%(%3d%%,%3d%%) ",capitalize(skill_table[sn].name), victim->pcdata->learned[sn], skill_table[sn].learn_scale_percent[victim->clss], (skill_table[sn].learn_scale_percent[victim->clss]==0? 100:skill_table[sn].learn_scale_percent[ch->clss])); } }else{ if (victim->level < lev && victim->pcdata->learned[sn]!=101){ if(ch->level<lev){ sprintf(buf,"%-18s n/a ", capitalize(skill_table[sn].name)); }else{ sprintf(buf,"%-18s n/a(%3d%%) ", capitalize(skill_table[sn].name), victim->pcdata->learned[sn]); } }else{ sprintf(buf,"%-18s %3d%% ",capitalize(skill_table[sn].name), victim->pcdata->learned[sn]); } } if (IS_NULLSTR(skill_list[lev])){ sprintf(linebuf,"\r\n Level %2d: %s",lev,buf); replace_string(skill_list[lev], linebuf); }else{ // append if ( ++skill_columns[lev] % 2 == 0){ sprintf(linebuf,"%s\r\n ",skill_list[lev]); replace_string(skill_list[lev], linebuf); }else{ // trim off the extra spaces strcpy(linebuf, skill_list[lev]); linebuf[str_len(linebuf)-6]='\0'; replace_string(skill_list[lev], linebuf); } sprintf(linebuf,"%s%s",skill_list[lev],buf); replace_string(skill_list[lev], linebuf); } } } if (IS_IMMORTAL(ch) || specially_granted_skills){ top_level= ABSOLUTE_MAX_LEVEL; }else{ top_level= LEVEL_HERO; } // return results if (!found){ if (ch==victim){ ch->println( "You know no skills." ); }else{ ch->println( "They know no skills." ); } }else{ for (lev = 1; lev < top_level; lev++){ if(lev==LEVEL_IMMORTAL){ if(IS_IMMORTAL(ch)){ sprintf(buf, "\r\n\r\n%s", makef_titlebar("SKILLS DISABLED FOR CHARACTER UNLESS GRANTED BELOW HERE")); }else{ sprintf(buf, "\r\n\r\n%s", makef_titlebar("SPECIALLY GRANTED SKILLS")); } buf[str_len(buf)-2]= '\0'; strcat(buf,"`x"); add_buf( output, buf); } if (!IS_NULLSTR(skill_list[lev])){ add_buf( output, skill_list[lev] ); } } add_buf( output, "\r\n"); ch->sendpage(buf_string(output)); free_buf(output); } // deallocate all memory used for (lev = 0; lev < MAX_LEVEL+2; lev++){ free_string(skill_list[lev]); } return; } /****************************************************************************/ // Kal - Dec 00 void do_cskinfo(char_data *ch, char * argument) { bool found = false; char buf[MSL], clss_name[MSL]; int sn, count, lev; BUFFER *output; int clss_no; if (IS_NULLSTR(argument)) { ch->wrapln( "CSKINFO - Class Skill Info - at what levels " "a particular class gets a skill and for how many trains."); ch->println( "Syntax: CSKINFO <class>" ); return; } argument = one_argument (argument, clss_name); for (clss_no = 0; !IS_NULLSTR(class_table[clss_no].name); clss_no++) { if (!str_cmp(clss_name, class_table[clss_no].short_name) || !str_prefix(clss_name,class_table[clss_no].name)) { found = true; break; } } if ( !found ) { ch->printlnf( "No class named '%s' exists. Use the 3-letter WHO names (Mag, Spf etc.)", clss_name); do_cskinfo(ch, ""); return; } // setup a buffer for info to be displayed output = new_buf(); count = 0; sprintf(buf,"Class Skill Info - all skills for `B%ss`x\r\n", class_table[clss_no].name); add_buf( output, buf); add_buf( output, "==Skill==========Level [Trains]=========="); add_buf( output, "==Skill==========Level [Trains]==\r\n"); for (lev=1; lev<=LEVEL_HERO; lev++) { for (sn = 0; !IS_NULLSTR(skill_table[sn].name) ; sn++) { if ( skill_table[sn].skill_level[clss_no]==lev && skill_table[sn].spell_fun == spell_null ) { count++; sprintf(buf, " %-20.20s %3d [%2d]", capitalize(skill_table[sn].name), lev, skill_table[sn].rating[clss_no]); add_buf( output, buf); if(count%2==0){ add_buf( output, "\r\n"); }else{ add_buf( output, " "); } } } } sprintf(buf, "%s %d skill%s total.", count%2==1?"\r\n":"", count, count==1?"":"s"); add_buf( output, buf); ch->sendpage(buf_string(output)); free_buf(output); return; } /**************************************************************************/ // shows skills, groups and costs (only if not bought) void list_group_costs(char_data *ch) { if (IS_NPC(ch)) return; int gn,sn,col; col = 0; ch->print(" `g===`MSkillgroup`g==================`xCP`g===="); ch->println("====`MSkillgroup`g==================`xCP`g===="); for (gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++) { if (!ch->gen_data->skillgroup_chosen[gn] && !ch->pcdata->skillgroup_known[gn] && IS_SKILLGROUP_SELECTABLE_FOR_CHAR(gn, ch)) { ch->printf(" `S[`M%-28.28s`x%2d`S]`x ", skillgroup_table[gn].name, skillgroup_table[gn].rating[ch->clss]); if (++col % 2 == 0){ ch->println(""); } } } if ( col % 2 != 0 ){ ch->println( "" ); } ch->println( "" ); col = 0; ch->print(" `g=`YSkill`g===========`xCP`g`BLevel`g="); ch->print("`g=`YSkill`g===========`xCP`g`BLevel`g="); ch->println("`g=`YSkill`g===========`xCP`g`BLevel`g="); for (sn = 0; !IS_NULLSTR(skill_table[sn].name); sn++) { // race restrictions // race restrictions if( IS_SET(skill_table[sn].flags,SKFLAGS_USE_RACE_RESTRICTIONS) && !IS_SETn(skill_table[sn].race_restrict_n, ch->race)) { continue; } // no_gain if(IS_SET(skill_table[sn].flags,SKFLAGS_NO_GAIN)) { continue; } if (!ch->gen_data->skill_chosen[sn] && ch->pcdata->learned[sn] == 0 && skill_table[sn].spell_fun == spell_null && skill_table[sn].rating[ch->clss] > 0 && skill_table[sn].skill_level[ch->clss] < LEVEL_IMMORTAL && skill_table[sn].skill_level[ch->clss]>0) { ch->printf(" `S[`Y%-16.16s`x%2d`B<%2d>`S]`x", skill_table[sn].name, skill_table[sn].rating[ch->clss], skill_table[sn].skill_level[ch->clss]); if (++col % 3 == 0) ch->print( "\r\n" ); } } if ( col % 3 != 0 ) ch->print( "\r\n" ); ch->println( "`x\r\n" ); ch->printlnf( "Creation points (CP): %3d Experience per level (XP): %d", ch->gen_data->points_chosen, exp_per_level(ch,ch->gen_data->points_chosen)); return; } /**************************************************************************/ void list_group_chosen(char_data *ch) { int gn,sn,col; col = 0; ch->print(" `g===`MSkillgroup`g==================`xCP`g===="); ch->println("====`MSkillgroup`g==================`xCP`g===="); for (gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++) { if (ch->gen_data->skillgroup_chosen[gn]) { ch->printf(" `S[`M%-28.28s`x%2d`S]`x ", skillgroup_table[gn].name, skillgroup_table[gn].rating[ch->clss]); if (++col % 2 == 0){ ch->println(""); } } } if ( col % 2 != 0 ){ ch->println( "" ); } ch->println( "" ); col=0; ch->print(" `g=`YSkill`g===========`xCP`g`BLevel`g="); ch->print("`g=`YSkill`g===========`xCP`g`BLevel`g="); ch->println("`g=`YSkill`g===========`xCP`g`BLevel`g="); for (sn = 0; !IS_NULLSTR(skill_table[sn].name); sn++) { if (ch->gen_data->skill_chosen[sn] && skill_table[sn].rating[ch->clss] > 0) { ch->printf(" `S[`Y%-16.16s`x%2d`B<%2d>`S]`x", skill_table[sn].name, skill_table[sn].rating[ch->clss], skill_table[sn].skill_level[ch->clss]); if (++col % 3 == 0) ch->print( "\r\n" ); } } if ( col % 3 != 0 ) ch->print( "" ); ch->println( "`x\r\n" ); ch->printlnf( "Creation points (CP): %3d Experience per level (XP): %d", ch->gen_data->points_chosen, exp_per_level(ch,ch->gen_data->points_chosen)); return; } /**************************************************************************/ int exp_per_level(char_data *ch, int points) { int expl,inc; if (IS_NPC(ch)){ return 1000; } expl = 1000; inc = 500; if(race_table[ch->race]->class_exp[ch->clss]<1000){ // safety check ch->println("BUG: exp_per_level for your race class combination is below 1000... please report this to the immortals!"); return 5000; } if (points < 40){ return race_table[ch->race]->class_exp[ch->clss]; } // processing points -= 40; while (points > 9) { expl += inc; points -= 10; if (points > 9) { expl += inc; inc *= 2; points -= 10; } } expl += points * inc / 10; return UMAX(1000, expl * race_table[ch->race]->class_exp[ch->clss]/1000); } /**************************************************************************/ // this procedure handles the input parsing for the skill generator bool parse_gen_groups(char_data *ch,char *argument) { char arg[MIL]; int gn,sn,i; if (IS_NULLSTR(argument)){ 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 (IS_NULLSTR(argument)) { ch->println( "You must provide a skill name." ); return true; } // can't take all the skills to over load the size on an int if (ch->pcdata->points>150) { ch->println( "There is a limit of 150 creation points..." ); ch->println( "you must remove other skills/groups before adding any more." ); return true; } gn = skillgroup_lookup(argument); if (gn != -1) { if (ch->gen_data->skillgroup_chosen[gn] || ch->pcdata->skillgroup_known[gn]) { ch->printlnf("You already the skillgroup '%s'.", skillgroup_table[gn].name); return true; } if ( !IS_SKILLGROUP_SELECTABLE_FOR_CHAR(gn, ch)) { ch->printlnf( "The skillgroup '%s' is not available to you.", skillgroup_table[gn].name ); return true; } // can't take all the skills to over load the size on an int if (ch->pcdata->points + skillgroup_table[gn].rating[ch->clss]>150) { ch->println( "There is a limit of 150 creation points..." ); ch->println( "you must remove other skills/groups before adding this group." ); return true; } ch->printlnf( "%s skillgroup added.", skillgroup_table[gn].name); ch->gen_data->skillgroup_chosen[gn] = true; ch->gen_data->points_chosen += skillgroup_table[gn].rating[ch->clss]; gn_add(ch,gn); ch->pcdata->points += skillgroup_table[gn].rating[ch->clss]; return true; } sn = skill_lookup(argument); if (sn != -1) { if (ch->gen_data->skill_chosen[sn] || ch->pcdata->learned[sn] > 0) { ch->println( "You already know that skill!" ); return true; } if ( !IS_SKILL_VALID_FOR_CLASS(sn, ch->clss) || IS_SPELL(sn)) { ch->println( "That skill is not available." ); return true; } // race restrictions if( IS_SET(skill_table[sn].flags,SKFLAGS_USE_RACE_RESTRICTIONS) && !IS_SETn(skill_table[sn].race_restrict_n, ch->race)) { ch->println( "That skill is not available to your race." ); return true; } if(IS_SET(skill_table[sn].flags,SKFLAGS_NO_GAIN)){ ch->println( "That skill is not available." ); return true; } // can't take all the skills to over load the size on an int if (ch->pcdata->points + skillgroup_table[gn].rating[ch->clss]>150) { ch->println( "There is a limit of 150 creation points..." ); ch->println( "you must remove other skills/groups before adding this skill." ); return true; } ch->printlnf( "%s skill added.", skill_table[sn].name); ch->gen_data->skill_chosen[sn] = true; ch->gen_data->points_chosen += skill_table[sn].rating[ch->clss]; ch->pcdata->learned[sn] = 1; ch->pcdata->points += skill_table[sn].rating[ch->clss]; return true; } ch->println( "No skills or groups by that name..." ); return true; } if (!strcmp(arg,"drop")) { if (argument[0] == '\0') { ch->println( "You must provide a skill to drop." ); return true; } gn = skillgroup_lookup(argument); if (gn != -1 && ch->gen_data->skillgroup_chosen[gn]) { ch->println( "Skillgroup dropped." ); ch->gen_data->skillgroup_chosen[gn] = false; ch->gen_data->points_chosen -= skillgroup_table[gn].rating[ch->clss]; gn_remove(ch,gn); // readd all the groups to make sure we don't lose any skills for (i = 0; !IS_NULLSTR(skillgroup_table[i].name); i++) { if (ch->gen_data->skillgroup_chosen[gn]){ gn_add(ch,gn); } } ch->pcdata->points -= skillgroup_table[gn].rating[ch->clss]; return true; } sn = skill_lookup(argument); if (sn != -1 && ch->gen_data->skill_chosen[sn]) { ch->println( "Skill dropped." ); ch->gen_data->skill_chosen[sn] = false; ch->gen_data->points_chosen -= skill_table[sn].rating[ch->clss]; ch->pcdata->learned[sn] = 0; ch->pcdata->points -= skill_table[sn].rating[ch->clss]; return true; } ch->println( "You haven't bought any such skill or group." ); return true; } if (!str_prefix(arg,"premise") || !str_prefix(arg,"explain")) { do_help(ch,"premise"); return true; } if (!str_prefix(arg,"list")) { ch->titlebar("LIST OF SKILLS AND SKILLSGROUPS STILL AVAILABLE"); list_group_costs(ch); return true; } if (!str_prefix(arg,"learned")) { ch->titlebar("LEARNED SKILLS AND SKILLGROUPS"); list_group_chosen(ch); ch->println( "You already have the following skills:" ); ch->println( "You have these skills as a mixture, of the default skills you get" ); ch->println( "with your race and class, plus the others you have added." ); do_skills(ch,""); return true; } if (!str_prefix(arg,"skillgroups") || !str_prefix(arg,"info")) { do_skillgroups(ch,argument); return true; } if (!str_prefix(arg,"spinfo")) { do_spinfo(ch,argument); return true; } if (!str_prefix(arg,"cspinfo")) { do_cspinfo(ch,argument); return true; } if (!str_prefix(arg,"cskinfo")) { do_cskinfo(ch,argument); return true; } return false; } /**************************************************************************/ // shows all skillgroups, or the sub-members of a skillgroup void do_skillgroups(char_data *ch, char *argument) { int gn,sn,col; if (IS_NPC(ch)) return; col = 0; if (argument[0] == '\0') { ch->titlebar("SKILLGROUPS YOU HAVE"); for (gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++) { if (ch->pcdata->skillgroup_known[gn]) { ch->printf( "%-25s ",skillgroup_table[gn].name); if (++col % 3 == 0) ch->print( "\r\n" ); } } if ( col % 3 != 0 ) ch->print( "\r\n" ); ch->titlebar(""); ch->println("To list all skillgroups type `=Cskillgroups all`x."); ch->println("To show the skills in a particular skillgroup type `=Cskillgroups <skgrp name>`x."); ch->titlebar(""); return; } if (!str_cmp(argument,"all")) // show all skillgroups { ch->titlebar("ALL SKILLGROUPS"); for (gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++) { if(!IS_SET(skillgroup_table[gn].flags, SKILLGROUP_CREATION_SELECTABLE)){ continue; } if(skillgroup_table[gn].remort){ ch->printf( "`S%d`x%-24s ", skillgroup_table[gn].remort, skillgroup_table[gn].name ); }else{ ch->printf( "%-25s ", skillgroup_table[gn].name ); } if (++col % 3 == 0) ch->print( "\r\n" ); } if ( col % 3 != 0 ){ ch->print( "\r\n" ); } ch->titlebar(""); return; } // show the sub-members of a group gn = skillgroup_lookup(argument); if (gn == -1) { ch->printlnf( "No skillgroup of the name '%s' exist.", argument ); ch->println( "Type 'skillgroups all' for a full listing." ); return; } ch->titlebarf("SKILLS WITHIN THE SKILLGROUP '%s'", uppercase(skillgroup_table[gn].name)); for (sn = 0; skillgroup_table[gn].skills[sn]>-1; sn++) { ch->printf( "%-25s ", skill_table[skillgroup_table[gn].skills[sn]].name); if (++col % 3 == 0) ch->print( "\r\n" ); } if ( col % 3 != 0 ) ch->print( "\r\n" ); ch->titlebar(""); } /**************************************************************************/ // new check improve system - Kal // trial code, not really completed yet. void new_check_improve( char_data *ch, int sn, bool success, int multiplier) { // standard situations where you can't improve if (IS_NPC(ch) || sn==-1 || IS_OOC(ch) || multiplier<1) { logf("1start %d\r\n",multiplier); return; } // can't improve by spamming #ifndef WIN32 if (ch->desc && ch->desc->repeat>5){ return; } #endif // store the perthousand improve table static short improve_chance_lookup_table[102]; // stored in range 1 ->10000 static bool initialise_table=true; if(initialise_table){ // calculate the improvement chances once, first time int i; double f; for(i=0; i<=100; i++){ // f=sqrt((100.0-i)/100); f=(100.0-i)/100; f=pow(100.0,f); f*=100; // put in 1->10000 range - increased precision improve_chance_lookup_table[i]=(short)f; //logf("improve_chance_lookup_table[%d]=%d", i, improve_chance_lookup_table[i]); } improve_chance_lookup_table[101]=1; initialise_table=false; } int maxlearn=skill_table[sn].learn_scale_percent[ch->clss]; if(maxlearn<1){ maxlearn=65; } if ( (!IS_SPELL(sn) && ch->level < skill_table[sn].skill_level[ch->clss]) || skill_table[sn].skill_level[ch->clss]==0 || skill_table[sn].rating[ch->clss] == 0 || ch->pcdata->learned[sn] <2 // 2% required - must prac at least once to improve || ch->pcdata->learned[sn] >=maxlearn) { return; // skill is not known, or past the point of improvement } if (number_range(1,4)!=1){ // make things harder new_check_improve( ch, sn, success, multiplier-1); return; } // check to see if the character has a chance to learn int chance= 8 * ch->modifiers[STAT_ME] + 2*ch->modifiers[STAT_IN]; chance /= ( multiplier * skill_table[sn].rating[ch->clss] * 4); chance += ch->level*3/4; if (number_range(1,1000) > chance){ // try again new_check_improve( ch, sn, success, multiplier-1); return; } // now that the character has a CHANCE to learn, see if they really have chance=improve_chance_lookup_table[ch->pcdata->learned[sn]]; int max_percent=UMAX(maxlearn, skill_table[sn].maxprac_percent[ch->clss]); if(max_percent>0 && max_percent<100){ chance=chance* max_percent/100; if(chance<1){ chance=1; } } if (!success){ chance/=2; chance = URANGE(1,chance,2500); } if (number_range(1,10000)> chance){ // try again new_check_improve( ch, sn, success, multiplier-1); return; } if (success){ ch->printlnf("*You have become better at `Y%s`x!", skill_table[sn].name); ch->pcdata->learned[sn]++; }else{ ch->printlnf("*You learn from your mistakes, and your `Y%s`x skill improves.", skill_table[sn].name); ch->pcdata->learned[sn] += number_range(1,3); ch->pcdata->learned[sn] = (unsigned char)UMIN(ch->pcdata->learned[sn],skill_table[sn].learn_scale_percent[ch->clss]); } ch->printlnf("*Your `Y%s`x is now at %d%%!!", skill_table[sn].name, ch->pcdata->learned[sn]); // calc how far they can prac it int maxprac=skill_table[sn].maxprac_percent[ch->clss]? skill_table[sn].maxprac_percent[ch->clss]: 50; if(!(ch->level>70 && ch->pcdata->learned[sn]<maxprac)){ gain_exp(ch,2 * skill_table[sn].rating[ch->clss]); } } /**************************************************************************/ // checks for skill improvement void check_improve( char_data *ch, int sn, bool success, int multiplier ) { if(IS_SET(skill_table[sn].flags,SKFLAGS_NEW_IMPROVE_SYSTEM) || HAS_CONFIG(ch,CONFIG_PRACSYS_TESTER)) { new_check_improve(ch, sn, success, multiplier); return; } if (IS_NPC(ch)) return; if (sn==-1){ return; } // can't improve in ooc rooms if (IS_OOC(ch)) return; // can't improve by spamming if (ch->desc && ch->desc->repeat>5) return; if ( (!IS_SPELL(sn) && ch->level < skill_table[sn].skill_level[ch->clss]) || skill_table[sn].skill_level[ch->clss]==0 || skill_table[sn].rating[ch->clss] == 0 || ch->pcdata->learned[sn] <1 || ch->pcdata->learned[sn] >99) return; // skill is not known // check to see if the character has a chance to learn int chance= 8 * ch->modifiers[STAT_ME] + 2*ch->modifiers[STAT_IN]; chance /= ( multiplier * skill_table[sn].rating[ch->clss] * 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 if (success){ chance = URANGE(5,100 - ch->pcdata->learned[sn], 95); if (number_percent() < chance) { ch->printlnf("You have become better at `Y%s`x!", skill_table[sn].name); ch->pcdata->learned[sn]++; if(!(ch->level>75 && ch->pcdata->learned[sn]<75)){ gain_exp(ch,2 * skill_table[sn].rating[ch->clss]); } } }else{ chance = URANGE(5,ch->pcdata->learned[sn]/2,30); if (number_percent() < chance) { ch->printf( "You learn from your mistakes, and your `Y%s`x skill improves.\r\n", skill_table[sn].name); ch->pcdata->learned[sn] += number_range(1,3); ch->pcdata->learned[sn] = UMIN(ch->pcdata->learned[sn],100); if(!(ch->level>70 && ch->pcdata->learned[sn]<75)){ gain_exp(ch,2 * skill_table[sn].rating[ch->clss]); } } } } /**************************************************************************/ // returns a skillgroup index number given the exact name int skillgroup_exact_lookup( const char *name ) { for( int gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++ ) { if ( !str_cmp( name, skillgroup_table[gn].name ) ){ return gn; } } return -1; } /**************************************************************************/ // returns a skillgroup index number given the name int skillgroup_lookup( const char *name ) { int gn; // perform exact match first gn=skillgroup_exact_lookup(name); if(gn>-1){ return gn; } // perform prefix match for( gn = 0; !IS_NULLSTR(skillgroup_table[gn].name); gn++ ) { if ( LOWER(name[0]) == LOWER(skillgroup_table[gn].name[0]) && !str_prefix( name, skillgroup_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; if(IS_NPC(ch)){ return; } if(!IS_SKILLGROUP_SELECTABLE_FOR_CHAR(gn, ch)){ return; } ch->pcdata->skillgroup_known[gn] = true; for (i = 0; skillgroup_table[gn].skills[i]>-1; i++) { if(IS_SKILL_VALID_FOR_CLASS(skillgroup_table[gn].skills[i], ch->clss)){ group_add(ch,skill_table[skillgroup_table[gn].skills[i]].name,false, skillgroup_table[gn].skillsvalue[i]); } } } /**************************************************************************/ // recusively removes a group given its number -- uses group_remove void gn_remove( char_data *ch, int gn) { int i; ch->pcdata->skillgroup_known[gn] = false; for (i = 0; skillgroup_table[gn].skills[i]>-1; i++) { if(IS_SKILL_VALID_FOR_CLASS(skillgroup_table[gn].skills[i], ch->clss)){ group_remove(ch,skill_table[skillgroup_table[gn].skills[i]].name); } } } /**************************************************************************/ // use for processing a skill or group for addition void group_add( char_data *ch, const char *name, bool deduct, int percent) { int sn,gn; if (IS_NPC(ch)){ // NPCs do not have skills return; } if(percent<0 || percent>101){ // safety check return; } sn = skill_exact_lookup(name); if (sn != -1) { if (ch->pcdata->learned[sn] < percent){ ch->pcdata->learned[sn] = percent; if (deduct){ ch->pcdata->points += skill_table[sn].rating[ch->clss]; } } return; } // if there wasn't a skill by the name, check for a group gn = skillgroup_lookup(name); if (gn != -1) { if (ch->pcdata->skillgroup_known[gn] == false) { ch->pcdata->skillgroup_known[gn] = true; if (deduct) ch->pcdata->points += skillgroup_table[gn].rating[ch->clss]; } 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 skillgroups gn = skillgroup_lookup(name); if (gn != -1 && ch->pcdata->skillgroup_known[gn] == true) { ch->pcdata->skillgroup_known[gn] = false; gn_remove(ch,gn); // be sure to call gn_add on all remaining skillgroups } } /**************************************************************************/ // Jarren - June 1999 void do_vault( char_data *ch, char *argument ) { char arg[MIL]; char_data *victim; int chance, accuracy; one_argument(argument,arg); if ( (chance = get_skill(ch,gsn_vault)) == 0 || (!IS_NPC(ch) && ch->level < skill_table[gsn_vault].skill_level[ch->clss])) { if (!IS_CONTROLLED(ch)) { ch->println( "Vault? What's that?" ); return; } } if (arg[0] == '\0') { victim = ch->fighting; if (!victim){ ch->println( "But you aren't fighting anyone!" ); return; } }else if ((victim = get_char_room(ch,arg)) == NULL){ ch->println( "They aren't here." ); return; } if (victim->position < POS_FIGHTING) { act("You'll have to let $M get back up first.",ch,NULL,victim,TO_CHAR); return; } if (victim == ch){ ch->println( "You try to pole vault onto yourself but miss horribly." ); return; } if (is_safe(ch,victim)) return; if ( !can_initiate_combat( ch, victim, 1 )) return; if (IS_AFFECTED(ch,AFF_CHARM) && ch->master == victim){ act("But $N is your friend!",ch,NULL,victim,TO_CHAR); return; } // modifiers // size and weight chance += ch->carry_weight / 250; chance -= victim->carry_weight / 200; if (ch->size < victim->size){ chance += (ch->size - victim->size) * 15; }else{ chance += (ch->size - victim->size) * 10; } // stats chance += ch->modifiers[STAT_ST]; chance -= victim->modifiers[STAT_QU]; chance -= GET_AC(victim,AC_BASH) /25; // speed if (IS_SET(ch->off_flags,OFF_FAST) || IS_AFFECTED(ch,AFF_HASTE)){ chance += 10; } if (IS_SET(victim->off_flags,OFF_FAST) || IS_AFFECTED(victim,AFF_HASTE)){ chance -= 30; } // level chance += (ch->level - victim->level); if (IS_CONTROLLED(ch)){ chance*=3; }; if (!IS_NPC(victim) && chance < get_skill(victim,gsn_dodge) ) chance -= 3 * (get_skill(victim,gsn_dodge) - chance); // now the attack if (number_percent() < chance ) { accuracy = 100 - get_skill(victim,gsn_vault); accuracy -= ch->modifiers[STAT_PR]/10; accuracy -= ch->modifiers[STAT_AG]/10; accuracy += victim->modifiers[STAT_QU]/9; if(ch->pcdata){ accuracy += ch->pcdata->tired/2; } if(accuracy < number_range(1,8)) { act("$n pole vaults at you delivering a powerfull blow to your head!",ch,NULL,NULL,TO_VICT); act("You pole vault at $n delivering a powerfull blow to $m head!",victim,NULL,NULL,TO_CHAR); act("$n pole vaults at $N delivering a powerfull blow to $M head.",ch,NULL,victim,TO_NOTVICT); accuracy = 2; }else{ act("$n pole vauls at you delivering a crushing blow to your abdomen!",ch,NULL,NULL,TO_VICT); act("You pole vault at $n delivering a crushing blow to $m abdomen!",victim,NULL,NULL,TO_CHAR); act("$n pole vaults at $N delivering a crushing blow to $M abdomen.",ch,NULL,victim,TO_NOTVICT); accuracy = 1; } check_improve(ch,gsn_vault,true,1); DAZE_STATE(victim, 3 * PULSE_VIOLENCE); WAIT_STATE(ch,skill_table[gsn_vault].beats); victim->position = POS_RESTING; damage(ch,victim,number_range(2,2 + accuracy * ch->size + chance/10), gsn_vault, DAM_BASH,false); }else{ damage(ch,victim,0,gsn_vault,DAM_BASH,false); act("You try to pole vault at $n but miss and fly right past $m!", victim,NULL,NULL,TO_CHAR); act("$n tries to pole vault at $N but flies right past $M.", ch,NULL,victim,TO_NOTVICT); act("You evade $n's pole vault, causing $m to fly right past you.", ch,NULL,NULL,TO_VICT); check_improve(ch,gsn_vault,false,1); WAIT_STATE(ch,skill_table[gsn_vault].beats * 3/2); } } /**************************************************************************/