RE: [Circle] [NEWBIE][code] crash in races

From: Jones E SrA 51CS/SCMMK (jonese@cs51.osan.af.mil)
Date: 11/06/96


> 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