Race Modification for CircleMUD 3.0 -by Nick C.- This mod is VERY bare, just the core for a good race system; Basically this mod is search and add, search and replace, etc... don't get too scared by the file size! :) Also, be warned, this is for an older patch level of CircleMUD 3.0, so some changes will be in order. In other words, if you expect it to work, expect to be making a lot of changes yourself. --- *** EMAIL SUPPORT IS *NOT* PROVIDED AT ALL *** --- First, let's open up the header (.h) files, as they are very important to the functioning of the program (.c) files. ************************* OPEN EDIT FILE: structs.h ************************* Search for --- /* NPC classes (currently unused - feel free to implement!) */ #define CLASS_OTHER 0 #define CLASS_UNDEAD 1 #define CLASS_HUMANOID 2 #define CLASS_ANIMAL 3 #define CLASS_DRAGON 4 #define CLASS_GIANT 5 --- Right below it, put the following --- /* PC races */ #define RACE_UNDEFINED -1 #define RACE_HUMAN 0 #define RACE_ELF 1 #define RACE_GNOME 2 #define RACE_FAIRY 3 #define NUM_RACES 4 --- Now search for --- #define CON_DELCNF1 15 /* Delete confirmation 1 */ #define CON_DELCNF2 16 /* Delete confirmation 2 */ --- Right below it, put the following --- #define CON_QRACE 17 /* Race? */ --- Now search for --- #define ITEM_ANTI_WARRIOR (1 << 15) /* Not usable by warriors */ #define ITEM_NOSELL (1 << 16) /* Shopkeepers won't touch it */ --- Right below it, put the following --- #define ITEM_ANTI_HUMAN (1 << 17) /* Not usable by Humans */ #define ITEM_ANTI_ELF (1 << 18) /* Not usable by Elves */ #define ITEM_ANTI_GNOME (1 << 19) /* Not usable by Gnomes */ #define ITEM_ANTI_FAIRY (1 << 20) /* Not usable by Fairies */ --- Now search for --- #define APPLY_SAVING_BREATH 23 /* Apply to save throw: breath */ #define APPLY_SAVING_SPELL 24 /* Apply to save throw: spells */ --- Right below it, put the following --- #define APPLY_RACE 25 /* Reserved */ --- Now search for --- /* general player-related info, usually PC's and NPC's */ struct char_player_data { char *name; /* PC / NPC s name (kill ... ) */ char *short_descr; /* for NPC 'actions' */ char *long_descr; /* for 'look' */ char *description; /* Extra descriptions */ char *title; /* PC / NPC's title */ byte sex; /* PC / NPC's sex */ byte class; /* PC / NPC's class */ --- Right below it, between byte class and the next variable, put the following --- byte race; /* PC / NPC's race */ --- Lastly search for --- struct char_file_u { /* char_player_data */ char name[MAX_NAME_LENGTH+1]; char description[EXDSCR_LENGTH]; char title[MAX_TITLE_LENGTH+1]; byte sex; byte class; --- Right below it, between byte class and the next variable, put the following --- byte race; --- ************************** CLOSE EDIT FILE: structs.h ************************** *********************** OPEN EDIT FILE: utils.h *********************** Search for --- #define GET_REAL_LEVEL(ch) \ (ch->desc && ch->desc->original ? GET_LEVEL(ch->desc->original) : \ GET_LEVEL(ch)) #define GET_CLASS(ch) ((ch)->player.class) --- Right below it, put the following --- #define GET_RACE(ch) ((ch)->player.race) --- Lastly search for --- #define IS_THIEF(ch) (!IS_NPC(ch) && \ (GET_CLASS(ch) == CLASS_THIEF)) #define IS_WARRIOR(ch) (!IS_NPC(ch) && \ (GET_CLASS(ch) == CLASS_WARRIOR)) --- Right below it, put the following --- #define IS_HUMAN(ch) (!IS_NPC(ch) && \ (GET_RACE(ch) == RACE_HUMAN)) #define IS_ELF(ch) (!IS_NPC(ch) && \ (GET_RACE(ch) == RACE_ELF)) #define IS_GNOME(ch) (!IS_NPC(ch) && \ (GET_RACE(ch) == RACE_GNOME)) #define IS_FAIRY(ch) (!IS_NPC(ch) && \ (GET_RACE(ch) == RACE_FAIRY)) --- ************************ CLOSE EDIT FILE: utils.h ************************ Now, lets go on to the .C files, the core of it all. *********************** OPEN EDIT FILE: class.c *********************** Search for --- const char *pc_class_types[] = { "Magic User", "Cleric", "Thief", "Warrior", "\n" }; --- Then put the following below it --- const char *race_abbrevs[] = { "Hum", "Elf", "Gno", "Fai", "\n" }; const char *pc_race_types[] = { "Human", "Elf", "Gnome", "Fairy", "\n" }; --- Now search for --- "Select a class:\r\n" " [C]leric\r\n" " [T]hief\r\n" " [W]arrior\r\n" " [M]agic-user\r\n"; --- And put the following right below it --- /* The menu for choosing a race in interpreter.c: */ const char *race_menu = "\r\n" "Select a race:\r\n" " [H]uman\r\n" " [E]lf\r\n" " [G]nome\r\n" " [F]airy\r\n"; --- Now search for --- case 'w': return CLASS_WARRIOR; break; case 't': return CLASS_THIEF; break; default: return CLASS_UNDEFINED; break; } } --- And block copy the following below it --- /* * 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 'h': return RACE_HUMAN; break; case 'e': return RACE_ELF; break; case 'g': return RACE_GNOME; break; case 'f': return RACE_FAIRY; break; default: return RACE_UNDEFINED; break; } } --- Now search for --- case 't': return 4; break; case 'w': return 8; break; default: return 0; break; } } --- Then place the following below it --- long find_race_bitvector(char arg) { arg = LOWER(arg); switch (arg) { case 'h': return 1; break; case 'e': return 2; break; case 'g': return 4; break; case 'f': return 8; break; default: return 0; break; } } --- Now replace the description of void roll_real_abils(...) with this one --- /* * Roll the 6 stats for a character... each stat is made of the sum of * the best 3 out of 4 rolls of a 6-sided die. Each class then decides * which priority will be given for the best to worst stats. Race also * affects stats. */ --- Now search for --- case CLASS_WARRIOR: ch->real_abils.str = table[0]; ch->real_abils.dex = table[1]; ch->real_abils.con = table[2]; ch->real_abils.wis = table[3]; ch->real_abils.intel = table[4]; ch->real_abils.cha = table[5]; if (ch->real_abils.str == 18) ch->real_abils.str_add = number(0, 100); break; } --- And directly below it, put this --- switch (GET_RACE(ch)) { case RACE_HUMAN: ++ch->real_abils.con; break; case RACE_ELF: ++ch->real_abils.dex; ++ch->real_abils.intel; --ch->real_abils.con; --ch->real_abils.str; break; case RACE_GNOME: ch->real_abils.str+=3; --ch->real_abils.dex; --ch->real_abils.intel; --ch->real_abils.cha; break; case RACE_FAIRY: ch->real_abils.dex+=2; ++ch->real_abils.wis; ++ch->real_abils.cha; ch->real_abils.str-=2; --ch->real_abils.con; break; } --- You should have still left the end of the function the same though, like: --- ch->aff_abils = ch->real_abils; } --- Okay, now, at the very END of the file, add this function --- int invalid_race(struct char_data *ch, struct obj_data *obj) { if ((IS_OBJ_STAT(obj, ITEM_ANTI_HUMAN) && IS_HUMAN(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_ELF) && IS_ELF(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_GNOME) && IS_GNOME(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_FAIRY) && IS_FAIRY(ch))) return 1; else return 0; } --- ************************ CLOSE EDIT FILE: class.c ************************ *************************** OPEN EDIT FILE: constants.c *************************** Search for --- /* CON_x */ const char *connected_types[] = { "Playing", "Disconnecting", "Get name", "Confirm name", "Get password", "Get new PW", "Confirm new PW", "Select sex", "Select class", "Reading MOTD", "Main Menu", "Get descript.", "Changing PW 1", "Changing PW 2", "Changing PW 3", "Self-Delete 1", "Self-Delete 2", --- And add the following below it --- "Select race", --- Lastly search for --- /* APPLY_x */ const char *apply_types[] = { "NONE", "STR", "DEX", "INT", "WIS", "CON", "CHA", "CLASS", "LEVEL", "AGE", "CHAR_WEIGHT", "CHAR_HEIGHT", "MAXMANA", "MAXHIT", "MAXMOVE", "GOLD", "EXP", "ARMOR", "HITROLL", "DAMROLL", "SAVING_PARA", "SAVING_ROD", "SAVING_PETRI", "SAVING_BREATH", "SAVING_SPELL", --- And add the following below it --- "RACE", --- *************************** CLOSE EDIT FILE: constant.c *************************** ******************** OPEN EDIT FILE: db.c ******************** Search for --- mob_proto[i].player.sex = t[2]; mob_proto[i].player.class = 0; --- Then put this after it --- mob_proto[i].player.race = 0; --- Now search for --- GET_SEX(ch) = st->sex; GET_CLASS(ch) = st->class; --- Then add the following below it --- GET_RACE(ch) = st->race; --- Lastly search for --- st->sex = GET_SEX(ch); st->class = GET_CLASS(ch); --- Then put this below it --- st->race = GET_RACE(ch); --- ********************* CLOSE EDIT FILE: db.c ********************* ************************* OPEN EDIT FILE: handler.c ************************* Search for --- case APPLY_SAVING_SPELL: GET_SAVE(ch, SAVING_SPELL) += mod; break; --- Put the following below it --- case APPLY_RACE: /* ??? GET_RACE(ch) += mod; */ break; --- Now search for --- void equip_char(struct char_data * ch, struct obj_data * obj, int pos) { int j; int invalid_class(struct char_data *ch, struct obj_data *obj); --- And add this below it --- int invalid_race(struct char_data *ch, struct obj_data *obj); --- Lastly search for the following --- if ((IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch)) || invalid_class(ch, obj)) { --- and REPLACE the entire thing with the following: --- if ((IS_OBJ_STAT(obj, ITEM_ANTI_EVIL) && IS_EVIL(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_GOOD) && IS_GOOD(ch)) || (IS_OBJ_STAT(obj, ITEM_ANTI_NEUTRAL) && IS_NEUTRAL(ch)) || invalid_class(ch, obj) || invalid_race(ch, obj)) { --- ************************** CLOSE EDIT FILE: handler.c ************************** ***************************** OPEN EDIT FILE: interpreter.c ***************************** Search for --- extern const char *class_menu; --- Then add this below it --- extern const char *race_menu; --- Now, search for (its right below it) --- sh_int load_room; int load_char(char *name, struct char_file_u * char_element); int parse_class(char arg); --- And add this... --- int parse_race(char arg); --- Now replace the following two CASE statements for the ones that already exist completely erase old case CON_QCLASS, and add this one plus the additional case CON_QRACE at the end of it... --- case CON_QCLASS: if ((GET_CLASS(d->character) = parse_class(*arg)) == CLASS_UNDEFINED) { SEND_TO_Q("\r\nThat's not a class.\r\nClass: ", d); return; } SEND_TO_Q(race_menu, d); SEND_TO_Q("\r\nRace: ", d); STATE(d) = CON_QRACE; break; case CON_QRACE: if ((GET_RACE(d->character) = parse_race(*arg)) == CLASS_UNDEFINED) { SEND_TO_Q("\r\nThat's not a race.\r\nRace: ", d); return; } if (GETPFILEPOS(d->character) < 0) GETPFILEPOS(d->character) = create_entry(GET_NAME(d->character); init_char(d->character); save_char(d->character, NOWHERE); SEND_TO_Q(motd, d); SEND_TO_Q("\r\n\n*** PRESS RETURN: ", d); STATE(d) = CON_RMOTD; sprintf(buf, "%s [%s] new player.", GET_NAME(d->character), d->host); mudlog(buf, NRM, LVL_IMMORT, TRUE); break; --- *************************** CLOSE EDIT FILE: interpre.c ***************************