Re: [code] GET_CLASS for multiclassing...

From: Thomas Arp (t_arp@stofanet.dk)
Date: 11/10/02


From: "peter dahlgren" <peter_dahlgren2002@YAHOO.SE>
Welcor wrote:
> >and then simple checks like this
>
> >for (i = 0; i < NUM_MULTICLASSES; i++) {
> >if (GET_CLASS(ch, i) == 0)
> >continue;
> >if (is_class(vict, GET_CLASS(ch, i)) != -1)
> >/* ch and vict has at least one common class */
> >do_stuff(tm)
> >}
>
> do you mean if(GET_CLASS(ch, i) == -1) ?
> because 0 is CLASS_WARRIOR...
> or maybe it should be 0, i'm confused, help? :)

Yes, it should be -1, then. Or rather, it should be 'CLASS_UNDEFINED',
which is defined as -1 AFAIR.

> by the way, i made a function that searches the current position in the
class array... > the position where the player gains levels that is...
> here goes
> int search_cur_class(struct char_data *ch)
> {
>  for(int i = 0; i < 6; i++)
>      if(GET_CLASS(ch, i) == -1)
>        return i-1;
Add this:
   return -1;
> }
> i know it's not much to look at, but since the classes goes in order,
> and -1 is an undefined value in the array, i want it to return the
> previous vaule, [i-1]

This will return the first unused index in the array, if the array is
initialized properly:

1, 2, -1, -1, -1, -1  -> 1
4, 6, 7, 1, -1, -1  -> 3
however, if the class array is badly initialized you'll get errant results:

-1, -1, -1, -1, -1, -1  -> -1
1, 2, 3, 4, 5, 6  -> (no return value in your example) -1

Depending on your intention this can be both good and bad. Some of the
things you need to look at when allowing multiclass are:

Make sure all players' class array is correctly initialized on char
creation. (see below)
Make sure people are (not) allowed to gain in a particular class.
Ie. a player plays a char to lvl 15 as a mage. He then changes over
and starts leveling as a cleric (as first multiclass). You must now
decide if he is allowed to gain anymore levels as a mage. And if not,
you must prevent him from multiclassing as a mage ( - m/c/m, if you
see what I mean) again, otherwise you must make sure the correct
level tables etc. are used.

I haven't seen anything from you that informs me if you save the level
people reach in a class. Consider this:

I'm level 30 warrior. I change to Mage. Do you somehow save my warrior
level, or do I just start from scratch as a level 0 mage with some
weapon skills ? When I reach level 11 as a mage, I decide I wish to
become a cleric. Will I just forget my mage spells ? If I decide to
be a thief, too, will I be able to cast any spells at all ? What if
I decided to go the other way and started as a thief ? Can I backstab ?

These are design questions, and should be answered before you start
coding _anything_[1]. Depending on your answers, you may decide on
using a different strategy than the one you've come up with.

Deciding whether or not a character can understand a spell is
easy, and we covered that one in the last mail. I've shown a way
to decide whether or not a player can use a spell, below.

> and, how do i make it set all values to -1 except the first class...?

In init_char, loop through the class array and set the class, like this:

#define NUM_MULTICLASSES 6 /* for easier expansion if need be */
int i;
for (i = 0; i < NUM_MULTICLASSES; i++)
  GET_CLASS(ch, i) = CLASS_UNDEFINED;

Then, when the player has chosen a class, just set the first class:

GET_CLASS(ch, 0) = <choice>;

Later on, and I guess you've discovered already, the most advanced
bit of coding in this endavour goes into the 'gain' part.

You earlier asked the list how spell_level() decides if a player
can use a spell. It doesn't. It simply sets a level for each
class which is able to cast the spell. This is then checked in
do_cast():

  if (GET_LEVEL(ch) < SINFO.min_level[(int) GET_CLASS(ch)]) {
    send_to_char(ch, "You do not know that spell!\r\n");
    return;
  }

Transform this to work with an array:

  int i, can_cast = FALSE;
  for (i = 0; i < NUM_MULTICLASSES; i++) {
    /* save cpu time */
    if (GET_CLASS(ch, i) == CLASS_UNDEFINED)
      break;
    if (GET_LEVEL(ch) > SINFO.min_level[(int) GET_CLASS(ch, i)])
      can_cast = TRUE;
  }
  if (!can_cast) {
    send_to_char(ch, "You do not know that spell!\r\n");
    return;
  }

As you can see, I'm stubbornly refusing to work with magic numbers.
Putting 'raw' numbers into your code will make it harder for you
to debug later, as well as making it near impossible for others
to understand if we're asked to help.

One of the most important things for you is to keep your class
array consistent. Certain optimizations, like the one I used above,
only work if there are no stray 'CLASS_UNDEFINED' in the beginning
of the array.

Welcor

[1] In my experience, design questions are seldom answered before
    most mud coding takes place. I figure this has something to
    do with most muds falling under the 'hobby' category, as well
    as some mud developers doesn't seem to ever have taken any
    classes in programming, much less project management.
    After all, who would wish to spend money on their hobby... :P
    (that's sarcasm, but it's hard to get through on text)

--
   +---------------------------------------------------------------+
   | FAQ: http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html |
   | Archives: http://post.queensu.ca/listserv/wwwarch/circle.html |
   | Newbie List:  http://groups.yahoo.com/group/circle-newbies/   |
   +---------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 06/25/03 PDT