Training

All these practices, and nothing to spend them on, right?  You gain 8 practices a level (if you have max wis), and only spend 2 every level (maybe) to get a new skill or spell.  How about training abilities?  Increase your con/int/wis to get more mana, or increase your str to get more damage; all without having to take up gear slots!

So, how does it work?

I experimented with a couple of ideas.  First was a simple “train” command – added a do_train command, put something in interpreter.c, and called it good.

But I didn’t like that idea.  It doesn’t make sense to walk out into the middle of nowhere and still be able to train your abilities.  So I decided to require players be before a trainer in order to train.  Only certain mobs will be designated trainers, so players will have to seek them out in order to improve their abilities.  This could be either someone in newbie school, or a dedicated trainer somewhere out in the middle of nowhere.

More after the jump

Here’s the basic code, added to spec_procs.c:

SPECIAL(trainer)
{

/* Make sure NPCs can't train */
 if (IS_NPC(ch) || !CMD_IS("train"))
 return (FALSE);

 int i;
 int rac = GET_RACE(ch);
 int cla = GET_CLASS(ch);

/*                          str add int wis dex con cha */
int race_bonus[][7] =     {{ 1,  0,  1,  2,  2,  1,  1 },  /* Human    */
 { 0,  0,  2,  3,  1,  0,  2 },  /* Elf      */
 { 1,  0,  3,  2,  0,  2,  0 },  /* Gnome    */
 { 0,  0,  0,  2,  2,  1,  3 },  /* Dwarf    */
 { 3,  0,  0,  1,  2,  2,  0 },  /* Orc      */
 { 2,  0,  1,  0,  3,  0,  2 },  /* Kobold   */
 { 2,  0,  2,  0,  0,  3,  1 }}; /* Minotaur */

/*                          str add int wis dex con cha */
int class_bonus[][7] =    {{ 0,  0,  2,  1,  0,  0,  0 },  /* Mage    */
 { 0,  0,  0,  2,  0,  0,  1 },  /* Cleric      */
 { 1,  0,  0,  0,  2,  0,  0 },  /* Thief    */
 { 2,  0,  0,  0,  0,  1,  0 },  /* Warrior    */
 { 0,  0,  0,  0,  1,  0,  2 },  /* Paladin      */
 { 0,  0,  1,  0,  0,  2,  0 },  /* Necro   */
 { 0,  0,  0,  0,  0,  0,  0 }}; /* TBD*/

int max_stats[7];

 for (i = 0; i < 7; i++) {
 max_stats[i] = 13 + race_bonus[rac][i] + class_bonus[cla][i];
 }
 char arg[MAX_INPUT_LENGTH];
 char *ability_str[8]   = { "str", "add", "int", "wis", "dex", "con", "cha", "\n" };
 int counti, len;

 /* # of practices per point is 5 (be sure to change at bottom of function as well) */

 if (GET_PRACTICES(ch) < 5)
 {
 send_to_char(ch, "You don't have enough practices.\r\n");
 return TRUE;
 }

/* If no argument, give the player some options */

 if (!*argument)
 {
 send_to_char(ch, "Train what?\r\n Available options are: str, int, wis, dex, con, cha\r\n");
 return TRUE;
 }

/* compare the argument with ability_str */

 one_argument(argument, arg);

 len = strlen(arg);
 for (counti = 0; counti < 8; counti++)
 if (!strncmp(arg, ability_str[counti], len))
 break;

/* So what are we training? */
/* We should really clean up the stat matrix...*/

/* Compare characters real_abils, not aff_abils (called by GET_STR) */

 if ((ch->real_abils.abilities[counti] < max_stats[counti]) && counti != 1 && counti != 7) {
 GET_PRACTICES(ch) -= 5; /* Reduce # of practices */
 ch->real_abils.abilities[counti] += 1;
 switch (counti) {
 case 0:
 send_to_char(ch, "You feel stronger.\r\n");
 break;
 case 2:
 send_to_char(ch, "You feel smarter.\r\n");
 break;
 case 3:
 send_to_char(ch, "You feel wiser.\r\n");
 break;
 case 4:
 send_to_char(ch, "You feel quicker.\r\n");
 break;
 case 5:
 send_to_char(ch, "You feel heartier.\r\n");
 break;
 case 6:
 send_to_char(ch, "You feel more likeable.\r\n");
 break;
 default:
 send_to_char(ch, "You can't train that.\r\n");
 break;
 } /* end of preceding switch */
 } /* end of preceding if */
 else {
 send_to_char(ch, "You can't train that");
 if (counti == 1)
 send_to_char(ch, ".\r\n");
 else
 send_to_char(ch, " any higher.\r\n");
 } /* end of preceding else */

save_char(ch); /* save before we leave */
return TRUE;
}

A brief note: at the beginning I have two arrays that describe race/class bonuses for various skills.  Obviously you may not want this, and merely allow players to train to a certain limit (say 18).

Of course, one problem with this approach is that each mob VNUM must be specifically assigned in spec_assign.c, like so:

ASSIGNMOB(10002, trainer);

Now, whenever someone is in front of a trainer and types “train”, they will get the message about training.

I also added a “train” command to interpreter.c which points to do_train in act.other.c, which returns to the character “You need to find a trainer.”

Pretty easy code.  The big issue here is to make sure you change the player’s base stats and not his modified stats.

Leave a comment