Class/Race Restructuring (and how to add Races if needed), Class Race/Stats Dependenicies Another Snippet by Edward Felch, dustlos@hotmail.com DISCLAIMER: Just because I can get this to work on my MUD and it doesn't on yours does not entitle you to whine and complain at me, make sure you back everything up, I take no responsibility whatsoever for problems that may arise from using the ideas and/or materials contained within this file. However, if you appeal to my good side, I may be willing to answer individual emails and attempt to assist you. This bit of snippet assumes that you are at least slightly above total newbie in programming prowess, you know how to compile, find *real* simple errors and fix them. This snippet will implement a different style of race/class than from stock. Anything starting with ( is comments/instructions for you while putting this in. Sadly, my interpreter.c is *highly* modified, so when it comes time for that part, I will paste most of my void nanny and *YOU* will need to modify it to fit on your MUD, sorry about this. Code Created On: Circle bpl17 w/ ASCII Pfiles (Del's bundle) This is an early release of the code here, I have not scanned through all the files and made sure that this is all you need to change, there will probably be some missing defines or externs, maybe a couple variables or funcs that no longer exist. If you need help for these simple things, email me. IF YOU DO NOT HAVE RACES GO TO THE BOTTOM OF THIS SNIPPET AND READ: ADDING IN RACES ************************************************************* ( Open up structs.h: ( At the very bottom, outside of any other structures or defines add this: struct generic_race_info { int number; // What number race this is char *name; // Full name of the race char *abbrev; // Shortened name of the race int craft_points; // How many crafts can they learn int exp_penalty; // EXP multiplier int skillz[3]; // Skill numbers for skills learned upon creation int innate; // Do they have an innate spell int stat_change[6]; // Bonus stats int old_age; // When they become old }; struct generic_class_info { int number; // What number class this is char *name; // Full name of the class char *abbrev; // Shortened name of the class int allowed_races[NUM_OF_RACES+1]; // 0 = this race can't be this class int stats_needed[6]; // Min value for each stat }; ( Still in structs.h, add in the following defines for some new STATEs, ( change XXX #define CON_QRACE XXX #define CON_QROLLING XXX ( Open up constants.c and add in the messages for the states (what you ( see when you type user) ( Open up utils.h, near the top add this in: extern struct generic_race_info races[NUM_OF_RACES]; extern struct generic_class_info classes[NUM_CLASSES]; ( Search utils.h for CLASS_ABBR, RACE_ABBR, CLASS_NAME, RACE_NAME ( And change or add these as necessary to these: #define RACE_NAME(ch) (IS_NPC(ch) ? "--" : races[(int)GET_RACE(ch)].name) #define CLASS_NAME(ch) (IS_NPC(ch) ? "--" : classes[(int)GET_CLASS(ch)].name) #define CLASS_ABBR(ch) (IS_NPC(ch) ? "--" : classes[(int)GET_CLASS(ch)].abbrev) #define RACE_ABBR(ch) (IS_NPC(ch) ? "--" : races[(int)GET_RACE(ch)].abbrev) ( Add this define in, somewhere near GET_CLASS #define GET_RACE(ch) ((ch)->player.race) ( Open up interpreter.c: ( Make sure all of these functions/variables are prototyped! void roll_real_abils(struct char_data * ch); int parse_race(char arg); int parse_general_class(char *arg, struct descriptor_data *d); void list_available_classes(struct descriptor_data *d); extern const char *race_menu; ( Here comes a big part on you, you need to adjust all this to fit your MUD ( properly, remove parts, have things go to different places. This is all ( in void nanny, look for CON_QSEX case CON_QSEX: /* query sex of new user */ switch (*arg) { case 'm': case 'M': d->character->player.sex = SEX_MALE; break; case 'f': case 'F': d->character->player.sex = SEX_FEMALE; break; default: SEND_TO_Q("That is not a sex..\r\n" "What IS your sex? ", d); return; } SEND_TO_Q("\r\n", d); SEND_TO_Q(race_menu, d); SEND_TO_Q("Race: ", d); STATE(d) = CON_QRACE; break; case CON_QRACE: load_result = parse_race(*arg); if (load_result == RACE_UNDEFINED) { SEND_TO_Q("\r\nThat's not a race.\r\nRace: ", d); return; } else GET_RACE(d->character) = load_result; SEND_TO_Q("\r\n*** PRESS RETURN TO ROLL STATS ***", d); STATE(d) = CON_QROLLING; break; case CON_QROLLING: switch (*arg) { case 'y': case 'Y': break; default: roll_real_abils(d->character); sprintf(buf, "\r\nStr: [%d/%d] Dex: [%d] Con: [%d] Int:" " [%d] Wis: [%d] Cha: [%d]", GET_STR(d->character), GET_ADD(d->character), GET_DEX(d->character), GET_CON(d->character), GET_INT(d->character), GET_WIS(d->character), GET_CHA(d->character)); SEND_TO_Q(buf, d); SEND_TO_Q("\r\n\r\nKeep these stats? (y/N)", d); return; } if ( GET_RACE(d->character) == RACE_VAMPIRE ) { GET_CLASS(d->character) = CLASS_VAMPIRE; SEND_TO_Q("\r\n", d); SEND_TO_Q(town_menu, d); SEND_TO_Q("Select a Town: ", d); STATE(d) = CON_QTOWN; } SEND_TO_Q("\r\n", d); list_available_classes(d); SEND_TO_Q("Select a Class: ", d); STATE(d) = CON_QCCLASS; break; case CON_QCLASS: load_result = parse_general_class(arg, d); switch (load_result) { case CLASS_UNDEFINED: SEND_TO_Q("\r\nThat's not a class you can't be!\r\nSelect a Class: ", d); return; default: GET_CLASS(d->character) = load_result; break; } SEND_TO_Q("\r\n", d); SEND_TO_Q(town_menu, d); SEND_TO_Q("Select a Town: ", d); STATE(d) = CON_QTOWN; break; case CON_QTOWN: load_result = parse_towns(*arg); if (load_result == TOWN_UNDEFINED) { SEND_TO_Q("\r\nThat's not a town.\r\nTown: ", d); return; } else GET_TOWN(d->character) = load_result; SEND_TO_Q("\r\n", d); SEND_TO_Q(deity_menu, d); SEND_TO_Q("Select a Deity: ", d); STATE(d) = CON_QDEITY; break; case CON_QDEITY: load_result = parse_deity(*arg); if (load_result == DEITY_UNDEFINED) { SEND_TO_Q("\r\nThat's not a deity.\r\nDeity: ", d); return; } else GET_DEITY(d->character) = load_result; SEND_TO_Q("\r\n", d); list_available_weapons(d); SEND_TO_Q("Select a Weapon: ", d); STATE(d) = CON_QWEAPON; break; case CON_QWEAPON: load_result = parse_general_weapon(arg, d); switch (load_result) { case WEP_UNDEFINED: SEND_TO_Q("\r\nThat's not a weapon you can use!\r\nSelect a Weapon: ", d); return; default: GET_MAIN_WEAPON(d->character) = load_result; break; } SEND_TO_Q("\r\n", d); /* Lets get the damn character up */ if (GET_PFILEPOS(d->character) < 0) GET_PFILEPOS(d->character) = create_entry(GET_PC_NAME(d->character)); /* Now GET_NAME() will work properly. */ init_char(d->character); save_char(d->character, NOWHERE); save_player_index(); sprintf(buf, "%s [%s] new player.", GET_NAME(d->character), d->host); mudlog(buf, NRM, LVL_IMMORT, TRUE); SEND_TO_Q(motd, d); SEND_TO_Q("\r\n*** PRESS RETURN: ", d); STATE(d) = CON_RMOTD; break; ( Create a new file races.c and put all of this into it: ( Once you are done, add races.c to the Makefile and depend if you need ( help READ the FAQ's and archives for Makefile/depend. /* Races.c contains structure and parsing */ #include "conf.h" #include "sysdep.h" #include "structs.h" #include "interpreter.h" #include "utils.h" #include "spells.h" struct generic_race_info races[NUM_OF_RACES] = { {0, "Human", "Hu", 1, 1, {-1, -1, -1}, -1, {0,0,0,0,0,0}, 90}, {1, "High Elf", "He", 0, 1.5, {-1, -1, -1}, -1, {-1,2,-2,1,0,0}, 2000}, {2, "Dwarf", "Dw", 0, 1.5, {-1, -1, -1}, -1, {1,-1,2,-1,0,-1}, 600}, {3, "Gnome", "Gn", 4, 1.5, {-1, -1, -1}, -1, {0,1,0,1,-1,-1}, 400}, {4, "Halfling", "Ha", 1, 1.5, {-1, -1, -1}, -1, {-2,2,-1,1,0,0}, 200}, {5, "Fairy", "Fa", 1, 1.5, {-1, -1, -1}, -1, {-2,2,-2,2,0,0}, 200}, {6, "Vampire", "Va", 0, 1.5, {-1, -1, -1}, -1, {2,1,-1,-1,-1,-2},-1}, {7, "Orc", "Or", 1, 1.5, {-1, -1, -1}, -1, {2,-1,1,-1,0,-2}, 60}, {8, "Astaroth", "As", 0, 1.5, {-1, -1, -1}, -1, {0,1,-2,1,1,-2}, -1}, {9, "Dark Elf", "De", 0, 1.5, {-1, -1, -1}, -1, {1,1,-1,-1,0,-2}, 2000}, {10, "Undead", "Un", 1, 1, {-1, -1, -1}, -1, {0,0,0,0,0,0}, -1}, {11, "Half Red", "Hr", -1, 1.5, {-1, -1, -1}, -1, {2,-2,1,-1,-1,-2},3000}, {12, "Half Green", "Hg", -1, 1.5, {-1, -1, -1}, -1, {1,1,1,-1,-2,-2}, 3000}, {13, "Half Silver", "Hs", -1, 1.5, {-1, -1, -1}, -1, {0,-1,0,1,-1,2}, 3000}, {14, "Half Copper", "Hc", -1, 1.5, {-1, -1, -1}, -1, {2,1,-1,-1,-1,-1},3000} }; /* The menu for choosing a race in interpreter.c: */ const char *race_menu = "\r\n" "Select a race:\r\n" "#) Name -= Str = Dex = Con = Int = Wis = Cha =-\r\n" "0) Human +0 +0 +0 +0 +0 +0\r\n" "1) High Elf -1 +2 -2 +1 +0 +0\r\n" "2) Dwarf +1 -1 +2 -1 +0 -1\r\n" "3) Gnome +0 +1 +0 +1 -1 +0\r\n" "4) Halfling -2 +2 -1 +1 +0 +0\r\n" "5) Fairy -2 +2 -2 +2 +0 +0\r\n" "6) Vampire +2 +1 -1 -1 -1 -2\r\n" "7) Orc +2 -1 +1 -1 +0 -2\r\n" "8) Astaroth +0 +1 -2 +1 +1 -2\r\n" "9) Dark Elf +1 -1 +2 -1 +0 -1\r\n" "C) Half Copper Dr +2 +1 -1 -1 -1 -1\r\n" "G) Half Green Dr +1 +1 +1 -1 -2 -2\r\n" "R) Half Red Dr +2 -2 +1 -1 -1 -2\r\n" "S) Half Silver Dr +0 -1 +0 +1 -1 +2\r\n" "U) Undead Being +0 +0 +0 +0 +0 +0\r\n" ; /* * The code to interpret a race letter (used in interpreter.c when a * new character is selecting a race). */ int parse_race(char arg) { arg = LOWER(arg); switch (arg) { case '0': return RACE_HUMAN; break; case '1': return RACE_HIGH_ELF; break; case '2': return RACE_DWARF; break; case '3': return RACE_GNOME; break; case '4': return RACE_HALFLING; break; case '5': return RACE_FAIRY; break; case '6': return RACE_VAMPIRE; break; case '7': return RACE_ORC; break; case '8': return RACE_ASTAROTH; break; case '9': return RACE_DARK_ELF; break; case 'c': case 'C': return RACE_HALF_COPPER; break; case 'g': case 'G': return RACE_HALF_GREEN; break; case 'r': case 'R': return RACE_HALF_RED; break; case 's': case 'S': return RACE_HALF_SILVER; break; case 'U': case 'u': return RACE_UNDEAD; break; default: return RACE_UNDEFINED; break; } } ( Open up class.c: ( At the very top, if comm.h isn't included, include it now ( Get rid of class_menu and parse_class, etc make sure you do this ( in all other files which extern those things, simple errors for you ( fix :) /* Main structure for classes */ // Races: Human H-Elf Dwarf Gnome Halfling Fairy Vampire Orc Astaroth D-Elf Undead H-R H-G H-S H-C // Stats: Str Dex Con Int Wis Cha struct generic_class_info classes[NUM_CLASSES] = { {0, "Mage", "Ma", {1,1,0,0,0,1, 0,0,1,1,1, 1,0,1,0}, {3,3,3,11,10,3}}, {1, "Elementalist", "El", {1,1,1,0,0,0, 0,1,0,0,1, 0,1,0,0}, {10,6,11,13,12,3}}, {2, "Mystic", "My", {1,0,0,1,1,1, 0,0,1,0,1, 0,0,0,0}, {5,5,8,14,14,10}}, {3, "Necromancer", "Ne", {1,0,0,0,0,0, 0,0,0,0,1, 0,0,0,0}, {3,3,12,12,12,3}}, {4, "Sorcerer", "So", {1,1,0,0,0,1, 0,0,1,1,1, 0,1,0,1}, {10,3,3,16,12,3}}, {5, "Priest", "Pr", {1,1,1,1,1,0, 0,1,0,1,0, 1,1,1,1}, {3,3,8,10,11,10}}, {6, "Avatar Trainee","At", {1,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0}, {3,3,3,15,16,11}}, {7, "Geomancer", "Ge", {1,1,0,0,0,1, 0,1,0,0,1, 0,1,0,1}, {3,3,12,12,14,8}}, {8, "Monk", "Mo", {1,0,1,0,0,0, 0,0,0,0,0, 1,1,1,1}, {12,12,12,14,14,10}}, {9, "Shapeshifter", "Sh", {1,1,1,1,1,1, 0,1,0,1,1, 0,0,0,0}, {14,3,14,10,14,3}}, {10, "Rogue", "Ro", {1,0,0,1,1,0, 0,1,0,1,1, 0,0,0,0}, {3,11,8,8,8,3}}, {11, "Skald", "Sk", {1,1,1,1,1,1, 0,1,1,1,1, 1,1,1,1}, {11,11,11,8,8,14}}, {12, "Despoiler", "De", {1,0,1,0,1,0, 0,1,0,1,1, 1,0,1,0}, {13,13,13,8,8,5}}, {13, "Assassin", "As", {1,0,0,0,1,0, 0,1,0,1,1, 0,1,0,1}, {14,16,12,14,8,3}}, {14, "Merchant", "Me", {1,1,1,1,1,1, 0,1,1,1,1, 1,1,1,1}, {8,8,8,14,10,14}}, {15, "Warrior", "Wa", {1,1,1,1,1,1, 0,1,1,1,1, 1,1,1,1}, {3,3,3,3,3,3}}, {16, "Faith Knight", "Fk", {1,0,0,0,0,0, 0,0,0,0,0, 0,0,0,0}, {16,12,14,14,16,12}}, {17, "Berserker", "Be", {1,0,1,0,0,0, 0,1,0,1,1, 1,1,1,1}, {16,8,16,3,3,3}}, {18, "Avenger", "Av", {1,1,1,0,0,0, 0,1,0,0,1, 1,0,1,0}, {14,14,14,8,8,8}}, {19, "Ranger", "Ra", {1,1,0,0,0,0, 0,0,0,1,0, 0,1,0,1}, {14,16,12,12,12,8}}, {20, "Vampire", "Va", {0,0,0,0,0,0, 1,0,0,0,0, 0,0,0,0}, {3,3,3,3,3,3}} }; ( Add these two functions in class.c, near the top but below the above void list_available_classes(struct descriptor_data *d) { int i = 0; sprintf(buf, "\r\nAvailable Classes: \r\n"); for (i = 0; i < NUM_CLASSES; i++) { if (!classes[i].allowed_races[(int)GET_RACE(d->character)]) continue; if (classes[i].stats_needed[R_STR] > GET_STR(d->character)) continue; if (classes[i].stats_needed[R_DEX] > GET_DEX(d->character)) continue; if (classes[i].stats_needed[R_CON] > GET_CON(d->character)) continue; if (classes[i].stats_needed[R_INT] > GET_INT(d->character)) continue; if (classes[i].stats_needed[R_WIS] > GET_WIS(d->character)) continue; if (classes[i].stats_needed[R_CHA] > GET_CHA(d->character)) continue; sprintf(buf + strlen(buf), "%s\r\n", classes[i].name); } SEND_TO_Q(buf, d); } int parse_general_class(char *arg, struct descriptor_data *d) { int i = 0; char *gofer = str_dup(arg); const char *def_classes[NUM_CLASSES][1]; for (i = 0; i < NUM_CLASSES; i++) def_classes[i][0] = str_dup("NONE"); for (i = 0; i < NUM_CLASSES; i++) { if (!classes[i].allowed_races[(int)GET_RACE(d->character)]) continue; if (classes[i].stats_needed[R_STR] > GET_STR(d->character)) continue; if (classes[i].stats_needed[R_DEX] > GET_DEX(d->character)) continue; if (classes[i].stats_needed[R_CON] > GET_CON(d->character)) continue; if (classes[i].stats_needed[R_INT] > GET_INT(d->character)) continue; if (classes[i].stats_needed[R_WIS] > GET_WIS(d->character)) continue; if (classes[i].stats_needed[R_CHA] > GET_CHA(d->character)) continue; def_classes[i][0] = str_dup(classes[i].name); } for (i = 0; i < NUM_CLASSES; i++) { if (!strcmp(def_classes[i][0], "NONE")) continue; if (is_abbrev(gofer, def_classes[i][0])) return i; } return CLASS_UNDEFINED; } ( Look for roll_real and replace it with this one void roll_real_abils(struct char_data * ch) { int i, j, temp; ubyte table[6]; ubyte rolls[4]; for (i = 0; i < 6; i++) table[i] = 0; for (i = 0; i < 6; i++) { for (j = 0; j < 4; j++) rolls[j] = number(1, 6); temp = rolls[0] + rolls[1] + rolls[2] + rolls[3] - MIN(rolls[0], MIN(rolls[1], MIN(rolls[2], rolls[3]))); table[i] = temp; } ch->real_abils.str_add = 0; ch->real_abils.intel = table[0]; ch->real_abils.wis = table[1]; ch->real_abils.dex = table[2]; ch->real_abils.str = table[3]; ch->real_abils.con = table[4]; ch->real_abils.cha = table[5]; if (ch->real_abils.str == 18 && IS_WARRIOR(ch)) ch->real_abils.str_add = number(0, 100); ch->real_abils.str += races[(int)GET_RACE(ch)].stat_change[R_STR]; ch->real_abils.dex += races[(int)GET_RACE(ch)].stat_change[R_DEX]; ch->real_abils.con += races[(int)GET_RACE(ch)].stat_change[R_CON]; ch->real_abils.intel += races[(int)GET_RACE(ch)].stat_change[R_INT]; ch->real_abils.wis += races[(int)GET_RACE(ch)].stat_change[R_WIS]; ch->real_abils.cha += races[(int)GET_RACE(ch)].stat_change[R_CHA]; ch->aff_abils = ch->real_abils; } ADDING IN RACES *************** ( Open up structs.h: ( Somewhere below the class defintions add this bit in, feel free to ( change these to whatever you want, but keep in mind what other parts ( would need altering. On my MUD, Vampire is a race that only has one ( class, the Vampric Class, so I assume there is a #define CLASS_VAMPIRE /* PC races */ #define RACE_UNDEFINED -1 #define RACE_HUMAN 0 #define RACE_HIGH_ELF 1 #define RACE_DWARF 2 #define RACE_GNOME 3 #define RACE_HALFLING 4 #define RACE_FAIRY 5 #define RACE_VAMPIRE 6 #define RACE_ORC 7 #define RACE_ASTAROTH 8 #define RACE_DARK_ELF 9 #define RACE_UNDEAD 10 #define RACE_HALF_RED 11 #define RACE_HALF_GREEN 12 #define RACE_HALF_SILVER 13 #define RACE_HALF_COPPER 14 #define NUM_OF_RACES 15 ( Look for struct char_file_u { and make sure byte race; is there ( as well as in struct char_player_data {