28 Nov, 2008, Igabod wrote in the 1st comment:
Votes: 0
ok, i've added hitroll and damroll to the do_train function and set the cost to (ch->hitroll / 8) + 1. i want the do_train function to display the cost but i can't figure out how to do it using strcat. i'll show you what i have:

strcpy (buf, "{cYou can train{W:{x\n\r");
if (ch->perm_stat[STAT_STR] < get_max_train (ch, STAT_STR))
strcat (buf, " {Rstr{x");
if (ch->perm_stat[STAT_INT] < get_max_train (ch, STAT_INT))
strcat (buf, " {Yint{x");
if (ch->perm_stat[STAT_WIS] < get_max_train (ch, STAT_WIS))
strcat (buf, " {Gwis{x");
if (ch->perm_stat[STAT_DEX] < get_max_train (ch, STAT_DEX))
strcat (buf, " {Bdex{x");
if (ch->perm_stat[STAT_CON] < get_max_train (ch, STAT_CON))
strcat (buf, " {Mcon{x");
if (ch->hitroll < 1001)
strcat (buf, "\n\r{cHitroll{W: {mCost is (hitroll / 8) + 1 trains per point{x");
if (ch->damroll < 1001)
strcat (buf, "\n\r{cDamroll{W: {mCost is (damroll / 8) + 1 trains per point{x");
strcat (buf, "\n\r{chp mana move{W: {mCost is 1 train per 10 points{x");


if anybody can tell me how to do this it would help to restore a small portion of my sanity… maybe…

[edit to add] i'm probably going to put a maximum on it later on but for now i just want this to display the cost instead of making the players do the math themselves.
28 Nov, 2008, Sharmair wrote in the 2nd comment:
Votes: 0
The strcat() is used to put an existing string at the end of another existing string, so, if you want to make
a string first. You will need a buffer to work with and for this example I am going to assume you have a
buffer called arg that is unused at this point in the code (a lot of functions use arg for a buffer used to
pull off args from the input to figure out what to do, and I would think this code would be used if there is
no input like train used with no args). You could use something like:
if (ch->hitroll < 1001){
sprintf(arg, "%d", (hitroll / 8) + 1);
strcat (buf, "\n\r{cHitroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
}

But, you could also just use the sprintf to make the whole sub string instead of all the strcats.
if (ch->hitroll < 1001){
sprintf(arg, "\n\r{cHitroll{W: {mCost is %d trains per point{x", (hitroll / 8) + 1);
strcat (buf, arg);
}

There are other ways like sending the output you have so far to the player and then using the sprintf
on buf directly, but I am assuming you want the full output in a string before you send anything.
28 Nov, 2008, tphegley wrote in the 3rd comment:
Votes: 0
Unrelated to your question Igabod, but what if someone strip all their gear before they train? Then the cost of training will be much less. Or am I seeing something different?
28 Nov, 2008, Scandum wrote in the 4th comment:
Votes: 0
Might be an idea to upgrade strcat while at it.

void cat_sprintf(char *dest, const char *fmt, …)
{
char buf[MAX_STRING_LENGTH];

va_list args;

va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);

strcat(dest, buf);
}


if (ch->hitroll < 1001)
{
cat_sprintf(buf, "\n\r{cHitroll{W: {m", (hitroll / 8) + 1);
}
28 Nov, 2008, Fizban wrote in the 5th comment:
Votes: 0
Scandum said:
Might be an idea to upgrade strcat while at it.

void cat_sprintf(char *dest, const char *fmt, …)
{
char buf[MAX_STRING_LENGTH];

va_list args;

va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);

strcat(dest, buf);
}


if (ch->hitroll < 1001)
{
cat_sprintf(buf, "\n\r{cHitroll{W: {m", (hitroll / 8) + 1);
}


I think that's definitely a great idea fora MUD, much like how I think Circle (and maybe some other codebases) using this:

send_to_char(ch, "The number is %d.\r\n", number);


is greatly superior to the older:

sprintf(buf, "The number is %d.\r\n", number);
send_to_char(buf, ch);
28 Nov, 2008, David Haley wrote in the 6th comment:
Votes: 0
Isn't ch_printf a fairly standard function by now?
28 Nov, 2008, Fizban wrote in the 7th comment:
Votes: 0
DavidHaley said:
Isn't ch_printf a fairly standard function by now?


Not in most codebases I've seen, specifically those from the rom half of the merc branch. Early CircleMUD didn't have anything with that format either but does now. (I think even Circle 3.1 didn't and only tbaMUD and CWG do but I may be mistaken on that.)
28 Nov, 2008, David Haley wrote in the 8th comment:
Votes: 0
Ah. Well, I agree, living without it is all kinds of painful. :wink:
29 Nov, 2008, Igabod wrote in the 9th comment:
Votes: 0
tphegley said:
Unrelated to your question Igabod, but what if someone strip all their gear before they train? Then the cost of training will be much less. Or am I seeing something different?

i hope the players are smart enough to remove their eq before training. thats the point of it cause i have a level 100 character who by default has a hitroll of 10 without eq and spells and with eq and spells it only reaches a little over 200. the damroll without eq and spells is around 3 i think and with eq and spells only reaches 100. this makes it difficult for them to kill mobs that actually give them exp so i decided to make it possible for them to train hr/dr. i may alter the cost in the future but that will require having players to test it out.
29 Nov, 2008, Igabod wrote in the 10th comment:
Votes: 0
Sharmair said:
The strcat() is used to put an existing string at the end of another existing string, so, if you want to make
a string first. You will need a buffer to work with and for this example I am going to assume you have a
buffer called arg that is unused at this point in the code (a lot of functions use arg for a buffer used to
pull off args from the input to figure out what to do, and I would think this code would be used if there is
no input like train used with no args). You could use something like:
if (ch->hitroll < 1001){
sprintf(arg, "%d", (hitroll / 8) + 1);
strcat (buf, "\n\r{cHitroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
}

But, you could also just use the sprintf to make the whole sub string instead of all the strcats.
if (ch->hitroll < 1001){
sprintf(arg, "\n\r{cHitroll{W: {mCost is %d trains per point{x", (hitroll / 8) + 1);
strcat (buf, arg);
}

There are other ways like sending the output you have so far to the player and then using the sprintf
on buf directly, but I am assuming you want the full output in a string before you send anything.

that resulted in "arg undeclared (first use in this function) should i use argument instead since it seems to be used in this function already?
29 Nov, 2008, Fizban wrote in the 11th comment:
Votes: 0
Igabod said:
Sharmair said:
The strcat() is used to put an existing string at the end of another existing string, so, if you want to make
a string first. You will need a buffer to work with and for this example I am going to assume you have a
buffer called arg that is unused at this point in the code (a lot of functions use arg for a buffer used to
pull off args from the input to figure out what to do, and I would think this code would be used if there is
no input like train used with no args). You could use something like:
if (ch->hitroll < 1001){
sprintf(arg, "%d", (hitroll / 8) + 1);
strcat (buf, "\n\r{cHitroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
}

But, you could also just use the sprintf to make the whole sub string instead of all the strcats.
if (ch->hitroll < 1001){
sprintf(arg, "\n\r{cHitroll{W: {mCost is %d trains per point{x", (hitroll / 8) + 1);
strcat (buf, arg);
}

There are other ways like sending the output you have so far to the player and then using the sprintf
on buf directly, but I am assuming you want the full output in a string before you send anything.

that resulted in "arg undeclared (first use in this function) should i use argument instead since it seems to be used in this function already?


No, argument has a very specific use. If I type 'train hitroll' hitroll is saved as argument. Just add: char arg; at the top of the function.
29 Nov, 2008, Zeno wrote in the 12th comment:
Votes: 0
"char arg"? Maybe I'm just tired, but… what? A single char..?
29 Nov, 2008, Igabod wrote in the 13th comment:
Votes: 0
act_move.c: In function `do_train':
act_move.c:1792: warning: passing arg 1 of `sprintf' makes pointer from integer without a cast
act_move.c:1794: warning: passing arg 2 of `strcat' makes pointer from integer without a cast
act_move.c:1797: warning: passing arg 1 of `sprintf' makes pointer from integer without a cast
act_move.c:1799: warning: passing arg 2 of `strcat' makes pointer from integer without a cast
act_move.c:1694: warning: `arg' might be used uninitialized in this function

i know they're only warnings but i just spent a LOT of time making my mud warning/error free this morning and don't wanna add more. what can be done to fix these?

[edit to add] nevermind thats not a problem, the problem is that now it crashes when i type train and for some reason gdb decided to freeze up upon crash
29 Nov, 2008, elanthis wrote in the 14th comment:
Votes: 0
You fix those errors by fixing the code. None of those sound like bogus warnings – each is quite serious. The first four sound like you're passing the wrong arguments to the functions (the compiler thinks they're integers, and if you're passing in integers, you're doin' it wrong). The last one means you're accessing a variable without guaranteeing that it has a value, which is a very easy way to crash your application.

That last error usually happens from code that is like the following (simplistic) example:

char* arg

if (foo > 10) {
arg = something_else;
}

do_blah(arg); /* arg has an undefined value if foo <= 10 */


Might explain your crashes. In general, you want to fix all your GCC warnings. They're there for a reason. The _only_ warnings I can ever think that GCC gives that are mostly harmless are the "unsigned vs signed comparison" warnings. Those actually do have a real purpose (avoiding for loops that have an upper bound larger than a signed int can hold, mostly), but in practice they're not a problem. Most people just paper over the problem by adding some quick casting, which doesn't actually remove the issue, it just shuts GCC up.
29 Nov, 2008, Igabod wrote in the 15th comment:
Votes: 0
so i need to add in a bit that says if ch->hitroll >= 1001 arg = "\n\rYour hitroll is at the maximum" or something like that?
29 Nov, 2008, elanthis wrote in the 16th comment:
Votes: 0
I'd imagine that the code probably just needs an else clause, versus some specific requirements. I don't think you posted the code in question – none of the code blocks above look like they're responsible for assigning to 'arg' at all.

It could be those lines that are sprinf()ing to arg. More examples of broken code:

char *arg;
sprintf(arg, "Some stuff."); /* copying a string into a random memory location */

char arg[MAX_STRING_LEN];
strcat(arg, "text to append"); /* appending text to a buffer that hasm't be initialized */


The last one is kinda tricky to understand, and is a great example of why I think it's retarded to be using C. You need to understand how strings in C work. In C, there really isn't any such thing as a string. A string is just an array of characters. The end of the array is marked by the special NUL byte (value of 0). When you create a buffer like the one in that example, all of its values are undefined. They could all be 0, they could all be 7, they could be some text you used before, or they could just be totally random. When strcat() tries to append to it, it is going to search for the end of the string already in that buffer. Since the buffer is uninitialized, and it could be filled with all 7s and no 0s, strcat() will just keep on searching for a 0 right past the end of the buffer and into some other random bit of memory. That is either going to result in a crash or it's going to result in strcat() copying the "text to append" data into some other important part of memory, corrupting it.

So it may not have anything to do with an if statement or loop or anything. You might just be defining a buffer or string wrong. I don't know. Post the entire function that's giving the errors and someone should be able to spot it for you.
29 Nov, 2008, Igabod wrote in the 17th comment:
Votes: 0
void do_train (CHAR_DATA * ch, char *argument)
{
char buf[MAX_STRING_LENGTH];
CHAR_DATA *mob;
sh_int stat = -1;
char *pOutput = NULL;
int cost;

if (IS_NPC (ch))
return;

/*
* Check for trainer.
*/
for (mob = ch->in_room->people; mob; mob = mob->next_in_room)
{
if (IS_NPC (mob) && IS_SET (mob->act, ACT_TRAIN))
break;
}

if (mob == NULL)
{
send_to_char ("You can't do that here.\n\r", ch);
return;
}

if (argument[0] == '\0')
{
sprintf (buf, "You have %d training sessions.\n\r", ch->train);
send_to_char (buf, ch);
argument = "foo";
}

cost = 1;

if (!str_cmp (argument, "str"))
{
if (class_table[ch->class].attr_prime == STAT_STR)
cost = 1;
stat = STAT_STR;
pOutput = "strength";
}

else if (!str_cmp (argument, "int"))
{
if (class_table[ch->class].attr_prime == STAT_INT)
cost = 1;
stat = STAT_INT;
pOutput = "intelligence";
}

else if (!str_cmp (argument, "wis"))
{
if (class_table[ch->class].attr_prime == STAT_WIS)
cost = 1;
stat = STAT_WIS;
pOutput = "wisdom";
}

else if (!str_cmp (argument, "dex"))
{
if (class_table[ch->class].attr_prime == STAT_DEX)
cost = 1;
stat = STAT_DEX;
pOutput = "dexterity";
}

else if (!str_cmp (argument, "con"))
{
if (class_table[ch->class].attr_prime == STAT_CON)
cost = 1;
stat = STAT_CON;
pOutput = "constitution";
}

else if (!str_cmp (argument, "hp"))
cost = 1;

else if (!str_cmp (argument, "mana"))
cost = 1;

else if (!str_cmp (argument, "move"))
cost = 1;

else if (!str_cmp (argument, "hitroll"))
cost = (ch->hitroll / 8) + 1;

else if (!str_cmp (argument, "damroll"))
cost = (ch->damroll / 8) + 1;

else
{
strcpy (buf, "{cYou can train{W:{x\n\r");
if (ch->perm_stat[STAT_STR] < get_max_train (ch, STAT_STR))
strcat (buf, " {Rstr{x");
if (ch->perm_stat[STAT_INT] < get_max_train (ch, STAT_INT))
strcat (buf, " {Yint{x");
if (ch->perm_stat[STAT_WIS] < get_max_train (ch, STAT_WIS))
strcat (buf, " {Gwis{x");
if (ch->perm_stat[STAT_DEX] < get_max_train (ch, STAT_DEX))
strcat (buf, " {Bdex{x");
if (ch->perm_stat[STAT_CON] < get_max_train (ch, STAT_CON))
strcat (buf, " {Mcon{x");
if (ch->hitroll < 1001)
sprintf(arg, "%d", (ch->hitroll / 8) + 1);
strcat (buf, "\n\r{cHitroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
if (ch->damroll < 1001)
sprintf(arg, "%d", (ch->damroll / 8) +1);
strcat (buf, "\n\r{cDamroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
strcat (buf, "\n\r{chp mana move{W: {mCost is 1 train per 10 points{x");

if (buf[strlen (buf) - 1] != ':')
{
strcat (buf, ".\n\r");
send_to_char (buf, ch);
}
else
{
/*
* This message dedicated to Jordan … you big stud!
*/
act ("You have nothing left to train, you $T!",
ch, NULL,
ch->sex == SEX_MALE ? "big stud" :
ch->sex == SEX_FEMALE ? "hot babe" : "wild thing", TO_CHAR);
}

return;
}

if (!str_cmp ("hp", argument))
{
if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;
ch->pcdata->perm_hit += 10;
ch->max_hit += 10;
ch->hit += 10;
act ("Your durability increases!", ch, NULL, NULL, TO_CHAR);
act ("$n's durability increases!", ch, NULL, NULL, TO_ROOM);
return;
}

if (!str_cmp ("mana", argument))
{
if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;
ch->pcdata->perm_mana += 10;
ch->max_mana += 10;
ch->mana += 10;
act ("Your power increases!", ch, NULL, NULL, TO_CHAR);
act ("$n's power increases!", ch, NULL, NULL, TO_ROOM);
return;
}

if (!str_cmp ("move", argument ))
{
if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;
ch->pcdata->perm_move += 10;
ch->max_move += 10;
ch->move += 10;
act ("Your stamina improves!", ch, NULL, NULL, TO_CHAR);
act ("$n's stamina improves!", ch, NULL, NULL, TO_ROOM);
return;
}

if (!str_cmp ("damroll", argument ))
{
if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;
ch->damroll += 1;
act ("You increase your damroll!", ch, NULL, NULL, TO_CHAR);
act ("$n's damroll increases!", ch, NULL, NULL, TO_ROOM);
return;
}

if (!str_cmp ("hitroll", argument ))
{
if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;
ch->hitroll += 1;
act ("You increase your hitroll!", ch, NULL, NULL, TO_CHAR);
act ("$n's hitroll increases!", ch, NULL, NULL, TO_ROOM);
return;
}

if (ch->perm_stat[stat] >= get_max_train (ch, stat))
{
act ("Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR);
return;
}

if (cost > ch->train)
{
send_to_char ("You don't have enough training sessions.\n\r", ch);
return;
}

ch->train -= cost;

ch->perm_stat[stat] += 1;
act ("Your $T increases!", ch, NULL, pOutput, TO_CHAR);
act ("$n's $T increases!", ch, NULL, pOutput, TO_ROOM);
return;
}

thats what it looks like with the code sharmair gave me installed in lines 104 - 113.
29 Nov, 2008, Sharmair wrote in the 18th comment:
Votes: 0
To define a buffer called arg like a lot of functions use, add:
char arg[MAX_INPUT_LENGTH];


up where buf etc are defined. Actually, MAX_INPUT_LENGTH is probably way more then you need
in this case (like 12 will handle any %d if that is all you are using it for - but it is good to have extra
just in case something gets changed) but will be ok.
The way C works, if you have not declared something before you use it, it will assume int. That is where
most of the warnings are from, but the crash is from it then trying to use that int as a pointer to a string.
As a few others have said, when you define a var in a function like this, the contents of the memory is
whatever it happened to be before you use it in the current function, and in this case it points to a place
you can't access so you get a crash (if it happened to point to valid memory, it might actually be worse
as you would write into that memory corrupting whatever was there before).
There is a way to make sprintf add to the end of an existing string though:
sprintf(buf+strlen(buf), "\n\r{cHitroll{W: {mCost is %d trains per point{x", (hitroll / 8) + 1);

I don't have the time right now to explain the working of this (and maybe also the difference between
a buffer and a char*), but will later if you wish.
29 Nov, 2008, David Haley wrote in the 19th comment:
Votes: 0
Sharmair said:
The way C works, if you have not declared something before you use it, it will assume int.

You cannot compile/link source code with undeclared variables. The warnings are due to assuming int for the purpose of continuing the compilation as far as possible, while still having to fail at the end.
30 Nov, 2008, Igabod wrote in the 20th comment:
Votes: 0
so this
if (ch->hitroll < 1001)
sprintf(arg, "%d", (ch->hitroll / 8) + 1);
strcat (buf, "\n\r{cHitroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");
if (ch->damroll < 1001)
sprintf(arg, "%d", (ch->damroll / 8) +1);
strcat (buf, "\n\r{cDamroll{W: {mCost is ");
strcat (buf, arg);
strcat (buf, " trains per point{x");

should look like this:
if (ch->hitroll < 1001)
sprintf(buf+strlen(buf), "\n\r{cHitroll{W: {mCost is %d trains per point{x", (ch->hitroll / 8) + 1));
if (ch->damroll < 1001)
sprintf(buf+strlen(buf), "\n\r{cDamroll{W: {mCost is %d trains per point{x, (ch->damroll / 8) + 1));

at least thats what i'm understanding, correct me if i'm wrong
0.0/22