22 May, 2009, boblinski wrote in the 41st comment:
Votes: 0
So, with these defines, do I just need to make sure the number "== x" is the exact number in order of race or class?

Therefore, if my pc_race_table is in order of:
null race, human, elf, giant, dwarf

And my class_table is in order of:
mage, cleric, thief, warrior, ranger..

My defines should look like:
#define IS_NULL_RACE(ch)	(ch->race == 0)
#define IS_HUMAN(ch) (ch->race == 1)
#define IS_ELF(ch) (ch->race == 2)
#define IS_GIANT(ch) (ch->race == 3)
#define IS_DWARF(ch) (ch->race == 4)


#define IS_MAGE(ch) ( ch->class == 1 )
#define IS_CLERIC(ch) ( ch->class == 2 )
#define IS_THIEF(ch) ( ch->class == 3 )
#define IS_WARRIOR(ch) ( ch->class == 4 )
#define IS_RANGER(ch) ( ch->class == 5 )


…?
22 May, 2009, David Haley wrote in the 42nd comment:
Votes: 0
You should do things like #define RACE_ELF to 2, but yes, you want the numbers to match the index of the appropriate class/race in the relevant table (keeping in mind that arrays are zero-indexed).
22 May, 2009, boblinski wrote in the 43rd comment:
Votes: 0
#define RACE_NULL(ch)	        (ch->race == 0)
#define RACE_HUMAN(ch) (ch->race == 1)
#define RACE_ELF(ch) (ch->race == 2)
#define RACE_GIANT(ch) (ch->race == 3)
#define RACE_DWARF(ch) (ch->race == 4)


#define CLASS_MAGE(ch) ( ch->class == 0 )
#define CLASS_CLERIC(ch) ( ch->class == 1 )
#define CLASS_THIEF(ch) ( ch->class == 2 )
#define CLASS_WARRIOR(ch) ( ch->class == 3 )
#define CLASS_RANGER(ch) ( ch->class == 4 )


?
Thanks for the help!
22 May, 2009, David Haley wrote in the 44th comment:
Votes: 0
Wait, no… You want to define the numbers and the tests separately. So,
#define RACE_HUMAN 1
#define IS_HUMAN(ch) ((ch)->race == 1)

or you can do ch->race == RACE_HUMAN literally instead of bothering with a macro that's basically the same thing.
22 May, 2009, boblinski wrote in the 45th comment:
Votes: 0
I can't believe I don't understand this..

Why do I need both? (is there an example with something similar I could look at?)

#define RACE_HUMAN 1
This makes it so when I call on "RACE_HUMAN" it returns the number 1?

#define IS_HUMAN(ch) (ch->race == 1)
What does this do.. and how does it link together with RACE_HUMAN?
22 May, 2009, David Haley wrote in the 46th comment:
Votes: 0
A #define is just literally expanded at compile time – it's not a function that you call. Think of it as a kind of automatic search-and-replace that the compiler does.
So yes, whenever you write RACE_HUMAN, the compiler will replace it with 1.

As written, every place that you have IS_HUMAN, it will be replaced with ch->race == 1.
But it's good form to minimize the frequency of "magic numbers" – numbers that just show up. It's much better to have a single location for the definition of what a human's racial number is. That is what RACE_HUMAN is for: a single place that defines the human's racial number and nowhere else will the number "1" appear to mean "human".
22 May, 2009, Hades_Kane wrote in the 47th comment:
Votes: 0
I don't think you need to do both.

If I understand it, they were recommending that as options.

the "#define IS_HUMAN(ch) (ch->race == 1) " makes it so that you can simply do:

if(IS_HUMAN(ch) && etc) in a check.

The other thing would work to where you would type:
if(ch->race == RACE_HUMAN)

Really though, I think I'd just pick one and go with it. You might have more options with the RACE_HUMAN thing just because, if you wanted, you could have checks that considered > and <, but I don't see any practical applications for that. I have mine defined in the IS_HUMAN manner and have had no problems.

I think people need to keep in mind, when they are suggesting things, you are just learning and sometimes its best just to keep it simple and just throwing out a solution without actually explaining why doesn't do you much good. That's why I've tried to propose what I felt to be the easiest and simplest solutions to anything you've asked that I've replied, and have tried to explain my reasoning behind them and what I understand they do, as to try to help you begin to be able to solve any of your issues yourself.

So yeah…
23 May, 2009, David Haley wrote in the 48th comment:
Votes: 0
It's better form to define RACE_HUMAN, and then reuse that. The options aren't mutually exclusive…

#define RACE_HUMAN 1
#define IS_HUMAN(ch) ((ch)->class == RACE_HUMAN)

It is preferable to have RACE_HUMAN defined because if you ever want to use the numeric value for human, you already have it as a constant. It's also a far better habit to get into than that of spewing numbers all over the code, which is sloppy, hard to read and a good source of potential error.

Getting into good habits is one of the most helpful things you can do for yourself. When good practice becomes second nature, you can spend more time worrying about actual code, and be confident that you will write higher-quality code naturally.

It's like learning to spell, really. If you have to think about grammar and spelling, you're thinking less about what you're actually writing. If grammar and spelling come completely naturally to you, the time you spend writing is spent on actual communication of ideas.
23 May, 2009, Hades_Kane wrote in the 49th comment:
Votes: 0
David Haley said:
It's better form to define RACE_HUMAN, and then reuse that. The options aren't mutually exclusive…


Here's the way I'm seeing it.

If he defines RACE_HUMAN as 1 and then can simply use 'if(ch->race == RACE_HUMAN)' to check for race, then why even bother with the IS_HUMAN macro? They aren't mutually exclusive, of course, but what's the point of having both? That's where I'm coming from, and I think what confused him to begin with, which is why I suggested there isn't really much of a reason to use both, so pick one and go with it. I can see the point in defining RACE_HUMAN as 1 and then having the macro reference RACE_HUMAN instead of the number if he was insistent on using the macro, I do understand that, but with neither present, I can't really see the point in bothering with both if RACE_HUMAN works just as well.

Is there something he and I are both misunderstanding?

If not, that's why I mentioned that it might be best to remember to keep things pretty simple for the people just learning. If there is no practical reason why he should use both if RACE_HUMAN would be the preferable option in an either/or situation, then I see no reason in confusing him by suggesting both. If there is a practical reason for using both rather than just using the RACE_HUMAN option, then I think it would benefit him more to have that reason explained to him, even if only briefly.
23 May, 2009, Kline wrote in the 50th comment:
Votes: 0
You don't NEED both, but it's better form to use at least the first.
boblinski said:
#define RACE_HUMAN 1
This makes it so when I call on "RACE_HUMAN" it returns the number 1?

Yes.

boblinski said:
#define IS_HUMAN(ch) (ch->race == RACE_HUMAN)
What does this do.. and how does it link together with RACE_HUMAN?

Fixed that for you. Alternatively, you don't even need IS_HUMAN(), and can simply check
if( ch->race == RACE_HUMAN )
for the same affect.

The point of this is that when you define "RACE_HUMAN" you can keep referencing it, and only have to change the fact that "RACE_HUMAN = 1" in a single spot in your code, instead of multiple places, and invariably miss one.
23 May, 2009, David Haley wrote in the 51st comment:
Votes: 0
I'm not sure what more to say really, or what question you're asking. It's better form to define constants at a granular level, and if need be, build other macros on top of macros, than to have a situation where you have to track down the same variable several times. As for having both, well, it was to illustrate how these things work – that's how you learn, after all. It's important to understand what the options are, and what different approaches entail. There's no point in keeping things so simple that it's just monkey-see, monkey-cut-and-paste – that doesn't help anybody. As for the advantages of each approach, several people, including myself, have explained the practical benefits of using constants. What is the remaining question?
23 May, 2009, Skol wrote in the 52nd comment:
Votes: 0
Davion said:
Skol said:
I wonder… could you set up a for loop that only happens at boot that then does the defines?

That's exactly how ROM handles its gsn's. You could likely just copy that system and plug it in with ease.

Whew, not crazy: check.
23 May, 2009, boblinski wrote in the 53rd comment:
Votes: 0
David Haley said:
I'm not sure what more to say really, or what question you're asking. It's better form to define constants at a granular level, and if need be, build other macros on top of macros, than to have a situation where you have to track down the same variable several times. As for having both, well, it was to illustrate how these things work – that's how you learn, after all. It's important to understand what the options are, and what different approaches entail. There's no point in keeping things so simple that it's just monkey-see, monkey-cut-and-paste – that doesn't help anybody. As for the advantages of each approach, several people, including myself, have explained the practical benefits of using constants. What is the remaining question?


Sorry it still takes me a while to get my head around things.

Thank you (and everyone else that posted) for being so understanding, and going into more detail for me.
24 May, 2009, boblinski wrote in the 54th comment:
Votes: 0
David Haley said:
boblinski said:
if (ch->level < 13)
{
shallow = 2;
}
else if (ch->level < 26)
{
shallow = 3;
}
else if (ch->level < 39)
{
shallow = 4;
}
else
shallow = 5;

shallow = MIN((ch->level / 13) + 2, 5);


Quote
$ make
gcc -Wall -O -ggdb -DNOCRYPT -DQMFIXES -c -o obj/scan.o scan.c
scan.c: In function `do_scan':
scan.c:75: warning: implicit declaration of function `MIN'
rm -f rom
gcc -O -ggdb -o rom obj/ability.o obj/act_comm.o obj/act_enter.o obj/act_info.o obj/a
ct_move.o obj/act_obj.o obj/act_wiz.o obj/alias.o obj/ban.o obj/bit.o obj/board.o obj
/comm.o obj/const.o obj/db.o obj/db2.o obj/effects.o obj/fight.o obj/flags.o obj/hand
ler.o obj/healer.o obj/hedit.o obj/ignore.o obj/interp.o obj/lookup.o obj/magic.o obj
/magic2.o obj/mem.o obj/mob_cmds.o obj/mob_prog.o obj/music.o obj/nanny.o obj/olc.o o
bj/olc_act.o obj/olc_mpcode.o obj/olc_save.o obj/recycle.o obj/save.o obj/scan.o obj/
skills.o obj/special.o obj/string.o obj/tables.o obj/update.o
obj/scan.o: In function `do_scan':
/cygdrive/c/qmud/src/scan.c:75: undefined reference to `_MIN'
/cygdrive/c/qmud/src/scan.c:79: undefined reference to `_MIN'
obj/scan.o: In function `do_scout':
/cygdrive/c/qmud/src/scan.c:193: undefined reference to `_MIN'
/cygdrive/c/qmud/src/scan.c:197: undefined reference to `_MIN'
collect2: ld returned 1 exit status
make: *** [rom] Error 1


line 75, 79, 193 and 197, all contain "shallow = MIN((ch->level / 13) + 2, 5);"
24 May, 2009, Kline wrote in the 55th comment:
Votes: 0
It may be defined as UMIN in most Diku-based games.
24 May, 2009, Skol wrote in the 56th comment:
Votes: 0
Yeah, it's UMIN (int, int); So like if you want to do a skill check with always some margin of error you'd do like chance = UMIN (get_skill(ch, gsn_backstab), 95), or in your case: shallow = UMIN((ch->level / 13) + 2, 5);
20 Aug, 2009, boblinski wrote in the 57th comment:
Votes: 0
Hi there.. I've got a new problem with my code-witting..

This is a piece of code in void interpret() in interp.c:
one_argument (argument, check_paralyze);

if (IS_AFFECTED2 (ch, AFF_PARALYSE))
{
if (!str_prefix(check_paralyze, "berserk") || !str_prefix(check_paralyze, "say") || !str_prefix(check_paralyze, "yell") || !str_prefix(check_paralyze, "tell"))
{
send_to_char ("Sure thing!\r\n", ch);
}
else
{
send_to_char ("Paralyzed dummy!\r\n", ch);
return;
}
}


It's working, but the problem is.. with stuff like- "!str_prefix(check_paralyze, "say")" … it recognizes.. s, sa and say and then lets the function continue…

But the problem is that my mud recognizes 's' as 'south' -not- 'say'.. is there a better way to write this code?

Thanks,
Bob.
20 Aug, 2009, Hades_Kane wrote in the 58th comment:
Votes: 0
I would assume you know that str_cmp would be used in regards to trying to match an exact comparison, right? I'm assuming that you are wanting to make it so that the command that is used is what passes this filter, regardless of whether or not they type it in full, correct?

Basing off of this assumption, you might do something like this:

if(!str_cmp(cmd_table[cmd].name, "say")


That might have to go in a for loop checking through all of your commands… rather than south, you might have to compare that to argument, then if found, compare that to the commands you are looking for (such as say).. I'm in a hurry so I don't have time to really give this enough thought, but regardless that might point you in the right direction.

Look in your interp.c in the interpret function in order to see how to define "cmd" and such and that might help too.

Good luck!
22 Aug, 2009, boblinski wrote in the 59th comment:
Votes: 0
Thanks for that fix!..

Here's my next prob :tongue:

I'm trying to write a spell that creates a MOB.. but only if there's not already a mob of the same VNUM in that room..

Am I meant to use this:
bool get_mob_vnum_room (CHAR_DATA * ch, sh_int vnum)
{
CHAR_DATA *mob;
for (mob = ch->in_room->people; mob; mob = mob->next_in_room)
if (IS_NPC (mob) && mob->pIndexData->vnum == vnum)
return TRUE;
return FALSE;
}


If so…

Here is what I tried…
if (get_mob_vnum_room(BONEWALL_DIR_NORTH))        /*magic2.c   line 607*/
{
send_to_char("There is already one here!\r\n", ch);
return;
}


And this is what happens:
Quote
$ make
gcc -Wall -O -ggdb -DNOCRYPT -DQMFIXES -c -o obj/magic2.o magic2.c
magic2.c: In function `spell_bonewall':
magic2.c:607: warning: implicit declaration of function `get_mob_vnum_room'
22 Aug, 2009, KaVir wrote in the 60th comment:
Votes: 0
get_mob_vnum_room() takes two arguments. You need to pass in 'ch' as well as the vnum.
40.0/63