Learned Skills/Spells created by: Mike Breuer This snippet was written for CircleMUD30bpl18, but it should work with any recent version of CircleMUD. Learned spells/skills are skills that are not automatically attained by characters, but are learned through some game event, such as being taught by a mobile, or studying a spellbook. If you use this code, please drop me a note at: blitzthethief@delta-quadrant.net You can also credit "Blitz" in your MUD if you are feeling generous. Before I get to the promised snippet, here is an example of a spec_proc I wrote to teach the "STUN" skill that I added. The proc is assigned to a mobile who sits in a room with a sign explaining that "fighter" type characters must pay 50,000 gold coins to be trained in the skill: SPECIAL(train_stun) { struct char_data *mob = (struct char_data *)me; char arg[MAX_INPUT_LENGTH]; if (FIGHTING(mob) || !AWAKE(mob)) return 0; if (!ch || IS_NPC(ch) || !cmd || !CMD_IS("learn")) return 0; one_argument(argument, arg); /* See if the player can learn... */ if (!*arg) { send_to_char("What do you want to learn?\r\n", ch); return 1; } else if (strn_cmp(arg, "stun", strlen(arg))) { act("$n tells you, 'I only teach the STUN skill.'", FALSE, mob, 0, ch, TO_VICT); return 1; } else if (GET_SKILL(ch, SKILL_STUN) > 0) { act("$n tells you, 'You already know how to do that.'", FALSE, mob, 0, ch, TO_VICT); return 1; } else if (GET_GOLD(ch) < 50000) { act ("$n tells you, 'You don't have enough money for my fee!'", FALSE, mob, 0, ch, TO_VICT); return 1; } else if (GET_CLASS(ch) != CLASS_WARRIOR) { act("$n tells you, 'I only train warriors!'", FALSE, mob, 0, ch, TO_VICT); return 1; } /* If we got this far, go ahead and set the skill */ SET_SKILL(ch, SKILL_STUN, 1); GET_GOLD(ch) -= 50000; act("$n teaches you the STUN skill.", FALSE, mob, 0, ch, TO_VICT); act("$n teaches $N a new skill.", TRUE, mob, 0, ch, TO_NOTVICT); act("$n charges you 50,000 gold coins for the lesson.", FALSE, mob, 0, ch, TO_VICT); return 1; } You may not use this exactly as I do, but it is a start. A more generic procedure could be used if you have many skills that you want to be able to teach in this manner. If you do use this proc, you will need to add the learn command. I also use spellbooks to teach spells, but the code changes to implement those are too extensive to include here, so I'll put them in another snippet. Now on to the snippet: ======================================================================= spells.h: Look for: struct spell_info_type { Add the following variable to the structure: ubyte learned; ===== spell_parser.c: Look for: void spello(int spl, const char *name, int max_mana, int min_mana, int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff); Change the function name and add a parameter: void _spello(int spl, const char *name, int max_mana, int min_mana, int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff, ubyte learned); -- Look for: void spello(int spl, const char *name, int max_mana, int min_mana, int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff) Add/change the following: #define spello(a,b,c,d,e,f,g,h,i,j) _spello((a),(b),(c),(d),(e),(f),(g),(h),(i),(j),0) #define spello_learned(a,b,c,d,e,f,g,h,i,j) _spello((a),(b),(c),(d),(e),(f),(g),(h),(i),(j),1) void _spello(int spl, const char *name, int max_mana, int min_mana, int mana_change, int minpos, int targets, int violent, int routines, const char *wearoff, ubyte learned) At the last line of the _spello function, add: spell_info[spl].learned = learned; -- Look for: #define skillo(skill, name) spello(skill, name, 0, 0, 0, 0, 0, 0, 0, NULL); Add: #define skillo_learned(skill, name) spello_learned(skill, name, 0, 0, 0, 0, 0, 0, 0, NULL); Note: I think the semi-colon can be dropped from each of these. -- Look for: void unused_spell(int spl) { Add to the bottom of the function: spell_info[spl].learned = 0; -- Look for: if (GET_LEVEL(ch) < SINFO.min_level[(int) GET_CLASS(ch)]) { send_to_char("You do not know that spell!\r\n", ch); return; } Change it to: if ((SINFO.learned == 0 && GET_LEVEL(ch) < SINFO.min_level[(int) GET_CLASS(ch)]) || (SINFO.learned && GET_SKILL(ch, spellnum) == 0)) { send_to_char("You do not know that spell!\r\n", ch); return; } ===== spec_procs.c: Look for: if (GET_LEVEL(ch) >= spell_info[i].min_level[(int) GET_CLASS(ch)]) { sprintf(buf, "%-20s %s\r\n", spell_info[i].name, how_good(GET_SKILL(ch, i))); strcat(buf2, buf); /* The above, ^ should always be safe to do. */ } Change to: if ((GET_LEVEL(ch) >= spell_info[i].min_level[(int) GET_CLASS(ch)] && spell_info[i].learned == 0) || (GET_SKILL(ch,i) > 0 && spell_info[i].learned)) { sprintf(buf, "%-20s %s\r\n", spell_info[i].name, how_good(GET_SKILL(ch, i))); strcat(buf2, buf); /* The above, ^ should always be safe to do. */ } -- Look for: if (skill_num < 1 || GET_LEVEL(ch) < spell_info[skill_num].min_level[(int) GET_CLASS(ch)]) { sprintf(buf, "You do not know of that %s.\r\n", SPLSKL(ch)); send_to_char(buf, ch); return (1); } Change to: if (skill_num < 1 || (GET_LEVEL(ch) < spell_info[skill_num].min_level[(int) GET_CLASS(ch)] && spell_info[skill_num].learned == FALSE) || (spell_info[skill_num].learned == TRUE && GET_SKILL(ch, skill_num) < 1)) { sprintf(buf, "You do not know of that %s.\r\n", SPLSKL(ch)); send_to_char(buf, ch); return (1); }