> Hi, >I have been trying to add races and classes to bpl11, and restrict access >to classes like this: >in interpreter.c, con_qclass, a switch(GET_CLASS), and then a check to >see if !can_be_mage, and if not, break out and go back to start. however, >a couple of problems: > >when i create a new character, i can choose any race, but when i try to >choose any class apart from the stock ones, say ninja, it crashes. i ran >gdb and got the following log: > > >#0 0x2a4e0 in set_title (ch=0x369e0c, title=0x0) at limits.c:200 This is where it sets the title for a new character >#1 0x22016 in init_char (ch=0x369e0c) at db.c:2279 This is where it is creating the new character >#2 0x29be4 in nanny (d=0x369678, arg=0xbffffb70 "n") at interpreter.c:1741 This is where you chose your class > >now, i was wondering what all this meant, and if anyone could help me >straigten it out. i know that races work, i have added them before, and i >know that i can also add new classes. it only seems to be when i try to >add something that checks for correct races in the classes that it >crashes. its probably something stupid that i have overlooked, but i dont >know... if it is please point it out to me :) > >Thanks in advance > >Glok Ok, here's what i did for my races and classes. I split up my files so my class stuff is in class.c and class.h, and my race stuff is in race.c and race.h I have race-dependant classes, so this may help you [Excerpt from class.c] Function: parse_class() int parse_class(struct descriptor_data *d, char arg) { arg = LOWER(arg); switch (arg) { case 'f': return CLASS_FIGHTER; break; case 'g': if (GET_RACE(d->character) == RACE_AARAKOCRA) return CLASS_NOTALLOWED; else return CLASS_GLADIATOR; break; case 'r': if (GET_RACE(d->character) == RACE_DWARF || GET_RACE(d->character) == RACE_MUL) return CLASS_NOTALLOWED; else return CLASS_RANGER; break; case 'd': if (GET_RACE(d->character) == RACE_AARAKOCRA || GET_RACE(d->character) == RACE_DWARF || GET_RACE(d->character) == RACE_HALF_GIANT || GET_RACE(d->character) == RACE_HALFLING || GET_RACE(d->character) == RACE_MUL || GET_RACE(d->character) == RACE_PTERRAN || GET_RACE(d->character) == RACE_THRI_KREEN) return CLASS_NOTALLOWED; else return CLASS_DEFILER; break; case 'p': if (GET_RACE(d->character) == RACE_DWARF || GET_RACE(d->character) == RACE_HALF_GIANT || GET_RACE(d->character) == RACE_HALFLING || GET_RACE(d->character) == RACE_MUL || GET_RACE(d->character) == RACE_PTERRAN || GET_RACE(d->character) == RACE_THRI_KREEN) return CLASS_NOTALLOWED; else return CLASS_PRESERVER; break; case 'c': if (GET_RACE(d->character) == RACE_PTERRAN) return CLASS_NOTALLOWED; else return CLASS_CLERIC; break; case 'u': if (GET_RACE(d->character) == RACE_DWARF || GET_RACE(d->character) == RACE_ELF || GET_RACE(d->character) == RACE_HALF_GIANT) return CLASS_NOTALLOWED; else return CLASS_DRUID; break; case 'b': if (GET_RACE(d->character) == RACE_AARAKOCRA || GET_RACE(d->character) == RACE_DWARF || GET_RACE(d->character) == RACE_ELF || GET_RACE(d->character) == RACE_HALF_GIANT || GET_RACE(d->character) == RACE_HALFLING || GET_RACE(d->character) == RACE_MUL || GET_RACE(d->character) == RACE_PTERRAN || GET_RACE(d->character) == RACE_THRI_KREEN) return CLASS_NOTALLOWED; else return CLASS_BARD; break; case 't': if (GET_RACE(d->character) == RACE_HALF_GIANT || GET_RACE(d->character) == RACE_THRI_KREEN) return CLASS_NOTALLOWED; else return CLASS_THIEF; break; case 'a': if (GET_RACE(d->character) == RACE_HALF_GIANT || GET_RACE(d->character) == RACE_HALFLING || GET_RACE(d->character) == RACE_MUL || GET_RACE(d->character) == RACE_THRI_KREEN) return CLASS_NOTALLOWED; else return CLASS_TRADER; break; case 's': return CLASS_PSIONICIST; break; default: return CLASS_UNDEFINED; break; } } [End of Excerpt] Ok, if you'll notice, i changed the parameters for parse_class to include a struct descriptor_data *d, this is to pass the descriptor data on the player so that I can use GET_RACE. There may be another way of doing this, but this is the first thing that came to mind when i was writing the section. Also, I have #defined CLASS_NOTALLOWED in my class.h file as -2. You just put it wherever the CLASS_x defines are. Ok, with that out of the way, let's move onto race.c and the parse_race command: [excerpt from race.c] int parse_race(char arg) { arg = LOWER(arg); switch (arg) { case 'a': return RACE_AARAKOCRA; break; case 'd': return RACE_DWARF; break; case 'e': return RACE_ELF; break; case 'l': return RACE_HALF_ELF; break; case 'g': return RACE_HALF_GIANT; break; case 'f': return RACE_HALFLING; break; case 'h': return RACE_HUMAN; break; case 'm': return RACE_MUL; break; case 'p': return RACE_PTERRAN; break; case 't': return RACE_THRI_KREEN; break; default: return RACE_UNDEFINED; break; } } [end of race.c] if you'll notice, the parse_race function is identical to the stock CircleMUD parse_class function. That is how it should be, unless you do strange things when you choose a race... In my case, I choose a race before i choose a class when creating a character. Ok, last but not least, here is the part in interpreter.c nanny() that does the work for me based on what i choose for race and class: [Excerpt from interpreter.c] case CON_QCLASS: if ((GET_CLASS(d->character) = parse_class(d, *arg)) == CLASS_UNDEFINED) { SEND_TO_Q("\r\nThat's not a class.\r\nClass: ", d); return; } if ((GET_CLASS(d->character) = parse_class(d, *arg)) == CLASS_NOTALLOWED) { SEND_TO_Q("\r\nThat class not available to your race.\r\nClass: ", d); return; } SEND_TO_Q(hometown_menu, d); SEND_TO_Q("\r\nHometown: ", d); STATE(d) = CON_QHOMETOWN; 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; } SEND_TO_Q(class_menu, d); SEND_TO_Q("\r\nClass: ", d); STATE(d) = CON_QCLASS; break; [end of interpreter.c] ok, if you look in the CON_QCLASS case statement, you can see where i did the checking. It is the if statement with the CLASS_NOTALLOWED in it. This way, if you choose a class that your race can't use, it will say 'That class is not available to your race.', and prompt you to select a class again. This method works great on my mud, and i have yet to have a crash because of it. Just remember that you need to choose the race first, by making sure the STATE(d) is set to CON_QRACE in the CON_QSEX case statement. If you have any questions, drop me an email, either here on the list or to jonese@cs51.osan.af.mil +-----------------------------------------------------------+ | Ensure that you have read the CircleMUD Mailing List FAQ: | | http://cspo.queensu.ca/~fletcher/Circle/list_faq.html | +-----------------------------------------------------------+
This archive was generated by hypermail 2b30 : 12/18/00 PST