Re: Dual Classing

From: Robert Moon (LegalWriter@msn.com)
Date: 06/04/00


----- Original Message -----
From: Chris Fischer <fischer@CET.COM>
>  So i go into utils.h then what do i do? rember i have NO CLUE at what any
> of this code means. A walkthrough mabey? Please?

You really need to move these kinds of posts to the newbie list or at least
have the courtesy of following the guidelines for participating on this list
and add "[NEWBIE]" to the subject line.  I get dozens and sometimes hundreds
of messages a day, and sometimes I just don't have the time or the desire to
hand-hold newbies who are in way too deep for their own good.  As has been
repeated to death on this list and in the FAQ and in the doc/ documents,
CircleMUD is not a "hello world" program for which to learn the C coding
language.  If you lack even the most basic skills as to not know what is
going on in ultils.h (a file which is mostly a collection of macros), then
you will surely flounder in nearly every other area.

Since I've already expended the time and energy on this message in the hopes
of future cooperation, I will continue and show you the basics of what you
should be doing.

First, let discuss what's happening in utils.h.  The header file utils.h is
#included in nearly every single .c file in the program, so anything
#defined in it will be accessible everywhere else.  As you will see, nearly
ever line in utils.h begins with the #define command (actually, it's called
a directive).  The #define directive simply tells the computer (actually the
precompiler, but who cares) to replace every instance of one string for
another.  We call that a macro.  If we scan utils.h from top to bottom, we
will first encounter the GET_CLASS() macro, which we will use later in your
archer thing.  Let's look at it.

#define GET_CLASS(ch)   ((ch)->player.chclass)

This line tells the computer to replace every instance of GET_CLASS(whoever)
with "whoever->player.chclass".  "whoever" in this case is a variable that
is defined as char_data.  What char_data and player.chclass are is a subject
beyond the scope of this discussion.  Essentially, though, it's asking for
the value in the character structure in the location called player.chclass
for "whoever."

In addition to the substitution powers of a #define directive, #defines can
also be used to create function-like macros, which can be passed arguments,
evaluate them, and return certain values based upon their findings.
Essentially, you can construct macros to use the same if-then-else logic as
an IF statement, which we do in the IS_NPC() macro.  Usually, these
function-macros are used to check if something is true or false.
Universally, functions and macros return a value of 0 if something in the
evaluation is false, and they return a non-zero value if everything that was
evaluated in the macro was true.

Let's look at a function-macro you need to copy, adapt, or use -- depending
on what you want to do -- for your archer thing:

#define IS_WARRIOR(ch)  (!IS_NPC(ch) && \
    (GET_CLASS(ch) == CLASS_WARRIOR))

The very first thing this macro does is call another macro, the IS_NPC()
macro, to determine if "ch" is a player or a mobile.  The exclamation point
is asking if ch is *not* an NPC.  If that evaluation is true -- meaning if
ch is *not* an NPC (he must be a player) -- then we continue with the macro.
Like an IF statement, the double ampersands, &&, are telling the macro that
the next evaluation must also be true for the macro to return a non-zero
value.  Since this line is rather long and would wrap awkwardly otherwise,
the original coder of this macro inserted a hard return to make viewing and
editing it easier.  However, since this is a header file, it determines the
end of a #define statement by a hard return, so we have to tell it to not
end just yet.  The way we do that is with the back-slash:  \.  The
back-slash must be the last character on a line before the hard return.  So,
assuming ch is not an NPC, we continue on the next line and encounter
another macro-within-this-macro:  GET_CLASS().

As discussed earlier, GET_CLASS(whoever) returns the value located in
player.chclass section of the player structure for "whoever."  Since the
memory storage location of player.chclass is a "byte," this must be a number
between -128 and 127.  In all likelihood, though, it will be a value from -1
to 3, assuming you haven't added any additional classes yet to your MUD.  -1
means this player doesn't have a class yet.  0 means he's a magic user; 1
means he's a cleric; 3 is thief; and 4 is warrior.  How do I know this?
Well, in structs.h, we globally define CLASS_MAGIC_USER as always being the
value of 0, CLASS_CLERIC as always being the value of 1, etc.  So during
character generation, when the player selects a class, the computer assigns
the value of CLASS_x to player.chclass for that player.  That's a bit beyond
the scope of this discussion, however.

Continuing with examining the IS_WARRIOR(ch) macro, we have already
determined that "ch" is a player.  Now we encounter GET_CLASS(ch).  Since
GET_CLASS() will return a value that is stored in player.chclass for a
particular player, if that value equals CLASS_WARRIOR (which is defined in
structs.h as being the value of 3), then we have finally reached the end of
our main macro and can return a non-zero value.  Since all evaluations in
the IS_WARRIOR() macro have returned non-zero values, IS_WARRIOR() itself
returns a non-zero vale, indicating that player is, indeed, a player and of
the warrior class.  If, however, the value in player.chclass equals 2 for
this player (meaning he's a thief), then we return a finding of 0 (meaning
FALSE) to the GET_CLASS() macro, which returns a value of 0 to the
IS_WARRIOR() macro.

Now that we have covered the philosophy of what is happening with the
macros, let's create an upgrade system for classes.  This is not the
walk-though you asked for.  I'm willing to explain the theories of how
things work, but I will not write your specific code.  Even if I tried to
write something to your specifications, you'd invariably complain to the
list that its not what you wanted and will ask again for more hand-holding.
That's not what this list is about.  So, try to follow along and use this
information to write your own unique code.

Note, this "upgrade" or mini-remort system for classes is ONE WAY of doing
this -- and is rather elementary in design.  It may not be what you're
looking for.  Let's create three new classes called CLASS_ARCHER,
CLASS_BOWMAN, and CLASS_SHARPSHOOTER.  Open structs.h and below:

#define CLASS_WARRIOR     3

we'll add:

#define CLASS_ARCHER     4
#define CLASS_BOWMAN     5
#define CLASS_SHARPSHOOTER     6

Close structs.h and open utils.h, moving to under:

#define IS_WARRIOR(ch)  (!IS_NPC(ch) && \
    (GET_CLASS(ch) == CLASS_WARRIOR))

We're now going to add the IS_blah macros for the archer, bowman, and
sharpshooter.  We're going to go in reverse order though, since CLASS_ARCHER
will be class from which the other two will spring.  Let's begin with the
sharpshooter.  We'll just copy IS_WARRIOR() macro.

#define IS_SHARPSHOOTER(ch)  (!IS_NPC(ch) && \
    (GET_CLASS(ch) == CLASS_SHARPSHOOTER))

Now, let's create bowman:

#define IS_BOWMAN(ch)  (!IS_NPC(ch) && \
    (GET_CLASS(ch) == CLASS_SHARPSHOOTER || \
     GET_CLASS(ch) == BOWMAN))

The above macro is saying that this player is considered a "bowman" if he is
currently of the class bowman or has upgraded into the class of
sharpshooter, using the philosophy that all skills and abilities that are
available to a bowman are also available to the more advanced sharpshooter.

Now we do the archer macro:

#define IS_ARCHER(ch)  (!IS_NPC(ch) && \
    (GET_CLASS(ch) == CLASS_SHARPSHOOTER || \
     GET_CLASS(ch) == CLASS_BOWMAN || \
     GET_CLASS(ch) == CLASS_ARCHER))

This last macro is asking if the character is (a) a player and (b) any of
the following:  an archer, bowman, or sharpshooter.  Again, this is based
upon the theory that anything an archer can do, so can a bowman and
sharpshooter.  Of course, this isn't utilizing the manner in which stock
CircleMUD assigns skills, but hopefully it explained what is going on in
utils.h well enough for you to get going with your own code.

Most important, however, is your need to go buy a book on how to program in
C.  A great one is "Teach Yourself C" by Herbert Schildt and published by
Osborne McGraw-Hill.  Better yet, take a community college course in it.
CircleMUD is NOT an appropriate place to learn, and this list is not the
newbie list.  Thanks in advance for your anticipated courtesy of not
spamming this list with further requests for walk-throughs and explanations
of the most basic elements of C-code design.

--Rob.
----------------
ICQ:  14598527


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     |  http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html  |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 04/10/01 PDT