17 Oct, 2013, Grieffels wrote in the 1st comment:
Votes: 0
So i've added in furnaces. Furnaces will only accept wood and coal item types. Well, it works with everything EXCEPT the arguments (put all furnace). If this is used, it bypasses the below code and still dumps everything into the furnace.

if (container->item_type == ITEM_FURNACE){
if ( obj->item_type != ITEM_COALSEAM)
{
send_to_char ("You can only put coal or wood in a furnace.",ch);
return;
}
}

Well, I went back to the "all" and "all." portion and added this
if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
{
if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == NULL )
{
send_to_char( "You do not have that item.\r\n", ch );
return;
}

if ( obj == container )
{
send_to_char( "You can't fold it into itself.\r\n", ch );
return;
}
if (container->item_type == ITEM_FURNACE){
if ( obj->item_type != ITEM_COALSEAM)
{
send_to_char ("You can only put coal or wood in a furnace.",ch);
return;
}
}

Again, I figured adding this would stop the put all furnace from allowing anything other than coal to be put in it. Can anyone see where I am going wrong here? I've also tried bracketing differently, running the if check slightly different using
if (container->item_type == ITEM_FURNACE && obj->item_type != ITEM_COALSEAM). This also works but goes back to the top as I said first. It works with put ANYTHING ELSE furnace and prints You can only put coal or wood in a furnace. However, it's just the put all portion that isn't working properly.

IE.
put all.ore furnace

You put a copper ore in a furnace.
You put a copper ore in a furnace.

put ore furnace

You can only put coal or wood in a furnace.

Edit by Kiasyn: code tags
17 Oct, 2013, MayaRK wrote in the 2nd comment:
Votes: 0
Hi Grief,

There are a few issues. First, str_cmp and str_prefix check to see if the argument and the string are NOT matching, so you will want to add a ! before each so that they check if the argument and string ARE matching. Second, you're checking if your argument is "all" or if it begins with "all." and neither can be true at once, so you'll need an || instead of &&. Lastly, you need to loop through the player's items since you're looking at what the player is carrying and not just a single item. Your code should look like this, and feel free to remove the comments, I just added them for clarity.

//This should be at top of code
bool found = FALSE; // if there is no coal found, the found variable will default to false and notify the player there is no coal in his/her inventory.
char arg1[MIL];
char arg2[MIL];
argument = one_argument(argument, arg1); // This is for the all and all. arguments
argument = one_argument(argument, arg2); // This is for the container, the furnace argument

//assuming you've got some checks in here for syntax safeguards to check if arg1[0] == '\0' or arg2[0] == '\0', etc

if ((container = get_obj_here(ch, NULL, arg2)) == NULL) { // Check to see if there is a container in the room
act_new("You see no $T here.", ch, NULL, arg2, TO_CHAR, POS_RESTING);
return;
}

if (container->item_type != ITEM_FURNACE) { // Check here so there is no need to check in the loop if the container is a furnace or not
send_to_char("That's not a furnace.\n\r", ch);
return;
}

if (!str_cmp(arg1, "all" ) || !str_prefix(arg1, "all.")) { // Checks if player enters "all" -or- "all." as the prefix to a string
for (obj = ch->carrying; obj != NULL; obj = obj_next) { // Need to add a loop because you're not just looking at one object, but all in inv
obj_next = obj->next_content;
if ((arg1[3] == '\0' || is_name(&arg1[4], obj->name)) { // Checks if player entered "all", if so all items are looked at OR
// if player entered "all.", then the 5th letter and beyond of all.<whatever> is
// compared with object name.
if ( obj == container ) {
send_to_char( "You can't fold it into itself.\r\n", ch );
continue; // Do NOT return;, a return will exit the loop AND the function. A continue will return to the top of the loop & continue on
}
if ( obj->item_type == ITEM_COALSEAM) {
obj_from_char(obj); // Take the obj from player
obj_to_obj(obj, container); // Place it in furnace
// Put some message here notifying player that object is now in furnace something like:
sprintf (buf, "You put %s in %s.\n\r", obj->short_descr, obj->short_descr);
send_to_char (buf, ch);
found = TRUE; // Added this so if no coal is found, you can notify player at bottom of function.
} else
continue; // Skip back to top of loop if obj has a different item type other than coal
}
}

if (!found) // No coal was found, so notify the player
send_to_char ("You don't have any coal.\n\r",ch);


There are a couple of other things you should do, like put an else after the string comparison if check, for players who only want to put one object in the furnace at a time.

Good luck. :wink:

Edit by Kiasyn: code tags
17 Oct, 2013, Kaz wrote in the 3rd comment:
Votes: 0
MayaRK said:
There are a few issues. First, str_cmp and str_prefix check to see if the argument and the string are NOT matching, so you will want to add a ! before each so that they check if the argument and string ARE matching.


For pedantry, because that's what coders do: the advice here is correct, but for the wrong reason.

str_cmp does not check to see if the argument and string are not matching. Instead, it returns the difference in the strings using a lexicographical comparison. That is, if there is a mismatch and the character on the left is less than the character on the right, the result will be less than 0. Likewise, if there is a mismatch, and the character on the left is greater than the character on the right, then the result will be greater than 0. If there strings are equal, then the difference is 0, and that is returned. This can be used for more than just comparing strings; it can also be used for ordering and sorting them.

The advice works because "!f(a,b)" is shorthand for "f(a,b) == 0".

(Also, if my reading of the DikuMUD source code is correct, str_cmp() is also case-insensitive).
17 Oct, 2013, MayaRK wrote in the 4th comment:
Votes: 0
Thanks for the clarification.

Just wanted to note that str_cmp() is case insensitive. strcmp() is case sensitive.

bool str_cmp(const char *astr, const char *bstr) {
if (astr == NULL) {
dbbug("Str_cmp: null astr.", 0);
return TRUE;
}

if (bstr == NULL) {
dbbug("Str_cmp: null bstr.", 0);
return TRUE;
}

for (; *astr || *bstr; astr++, bstr++) {
if (LOWER(*astr) != LOWER(*bstr))
return TRUE;
}

return FALSE;
}


Edit by Kiasyn: Code Tags
17 Oct, 2013, Kaz wrote in the 5th comment:
Votes: 0
Oh, now that's interesting, and isn't a lexicographical comparison at all. It looks as thought someone rewrote it to add some debug statements and couldn't figure out why -1 and +1 were in there. Here's the original from DikuMUD:

/* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2  */
/* scan 'till found different or end of both */
int str_cmp(char *arg1, char *arg2)
{
int chk, i;

for (i = 0; *(arg1 + i) || *(arg2 + i); i++)
if (chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))
if (chk < 0)
return (-1);
else
return (1);

return(0);
}


I don't recall the exact derivative that the OP has. Probably worth what str_cmp() does *before* using it as a comparator for sorting ;)
17 Oct, 2013, Sharmair wrote in the 6th comment:
Votes: 0
Grieffels said:
So i've added in furnaces. Furnaces will only accept wood and coal item types. Well, it works with everything EXCEPT the arguments (put all furnace). If this is used, it bypasses the below code and still dumps everything into the furnace.

if (container->item_type == ITEM_FURNACE){
if ( obj->item_type != ITEM_COALSEAM)
{
send_to_char ("You can only put coal or wood in a furnace.",ch);
return;
}
}

The do_put function is divided into three main sections, the first pulls off arguments and does basic validation, the
second handles the single object case, and the third the multi object case. I am unclear on where exactly you added
this, though it should be in the second section. But what confuses me is:
Grieffels said:
Well, I went back to the "all" and "all." portion and added this
if ( str_cmp( arg1, "all" ) && str_prefix( "all.", arg1 ) )
{
if ( ( obj = get_obj_carry( ch, arg1, ch ) ) == NULL )
{
send_to_char( "You do not have that item.\r\n", ch );
return;
}

if ( obj == container )
{
send_to_char( "You can't fold it into itself.\r\n", ch );
return;
}
if (container->item_type == ITEM_FURNACE){
if ( obj->item_type != ITEM_COALSEAM)
{
send_to_char ("You can only put coal or wood in a furnace.",ch);
return;
}
}

Again, I figured adding this would stop the put all furnace from allowing anything other than coal to be put in it. Can anyone see where I am going wrong here?

This is the start of the single object case (not the multi object) and is where you should have added the code that does work. The if at
the start of this is saying 'do this if arg1 is not "all" and also does not start with "all."', that is, the single object case. The multi object case
starts at the else to this if and is quite a ways down and starts with a loop. That loop has a rather long if statement that looks something
like this (this is ROM2.4b6):
if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
&& can_see_obj( ch, obj )
&& WEIGHT_MULT(obj) == 100
&& obj->wear_loc == WEAR_NONE
&& obj != container
&& can_drop_obj( ch, obj )
&& get_obj_weight( obj ) + get_true_weight( container )
<= (container->value[0] * 10)
&& get_obj_weight(obj) < (container->value[3] * 10))
{

If this condition is true, the object is moved, so you would want to add your new condition to make it look something like:
if ( ( arg1[3] == '\0' || is_name( &arg1[4], obj->name ) )
&& can_see_obj( ch, obj )
&& WEIGHT_MULT(obj) == 100
&& obj->wear_loc == WEAR_NONE
&& obj != container
&& can_drop_obj( ch, obj )
&& get_obj_weight( obj ) + get_true_weight( container )
<= (container->value[0] * 10)
&& get_obj_weight(obj) < (container->value[3] * 10)
&& (container->item_type != ITEM_FURNACE || obj->item_type == ITEM_COALSEAM))
{

Note that this is the reverse case from what you used as it is the case that you DO move the item.

Edit to add:
I am making the assumption that in the validation part of the function you have added a clause to the
container check to allow ITEM_FURNACE type as a valid container, and in this code I am assuming the
new type also uses the container flags, capacity etc of normal containers. If by chance you have not
thought of that at all, I can see a door on a furnace, it being full and even things like a campfire that
might be a furnace type object but you put the wood/coal on instead of in.
17 Oct, 2013, Nathan wrote in the 7th comment:
Votes: 0
Kaz said:
Oh, now that's interesting, and isn't a lexicographical comparison at all. It looks as thought someone rewrote it to add some debug statements and couldn't figure out why -1 and +1 were in there. Here's the original from DikuMUD:

/* returns: 0 if equal, 1 if arg1 > arg2, -1 if arg1 < arg2  */
/* scan 'till found different or end of both */
int str_cmp(char *arg1, char *arg2)
{
int chk, i;

for (i = 0; *(arg1 + i) || *(arg2 + i); i++)
if (chk = LOWER(*(arg1 + i)) - LOWER(*(arg2 + i)))
if (chk < 0)
return (-1);
else
return (1);

return(0);
}


I don't recall the exact derivative that the OP has. Probably worth what str_cmp() does *before* using it as a comparator for sorting ;)


That's some pretty strange stuff. Not sure why they're using that pointer arithmetic instead of something more clear. For curiousity's sake does anyone know why they wouldn't have just used normal array access?

I believe strcmp is the the string comparison function from the C string library (string.h). Not sure why they chose to implement a string comparison, but I'd guess either the standard one didn't exist then or wasn't common OR they wanted it to have slightly different behavior.

int strcmp ( const char * str1, const char * str2 );

The standard one from string.h returns 0 if true and integers greater/less than 0 dependent on comparing the character at a particular point in the string. To quote the Internet (http://www.cplusplus.com/reference/cstri...)

Quote
Returns an integral value indicating the relationship between the strings:
A zero value indicates that both strings are equal.
A value greater than zero indicates that the first character that does not match has a greater value in str1 than in str2; And a value less than zero indicates the opposite.
17 Oct, 2013, Sharmair wrote in the 8th comment:
Votes: 0
As far as the str_cmp() tangent in this thread, you would have to ask the authors of the DIKU code why they did
it the way they did. But I would think it was just the way the coder at the time felt comfortable using.
At the time it was written some of the C language let alone the run time library were in a state of flux. In at
least some versions of DIKU, there is a commented out strdup function that does exactly what the library function
does, and I have seen some of the same thing in other code, including having declarations of common library
functions in the code. But in the case of str_cmp, there was not a standard case insensitive library function at
the time (I am not even sure if there is now, though most compilers have one like _stricmp). As for why the Merc
coders changed it to return bool, it was not that they did not know what the -1 and 1 meant (actually a change
from the way strcmp works as strcmp probably will not return just +/-1 in those cases) but was in the theme of
Merc to simplify everything and strip out everything they could (Merc is actualy a more primitive codebase than
DIKU). In the code, str_cmp is only used for checking equality so it just does what it has to.
18 Oct, 2013, Davion wrote in the 9th comment:
Votes: 0
Sharmair said:
But in the case of str_cmp, there was not a standard case insensitive library function at the time (I am not even sure if there is now, though most compilers have one like _stricmp).


Is it not strcasecmp now?
18 Oct, 2013, Sharmair wrote in the 10th comment:
Votes: 0
Davion said:
Sharmair said:
But in the case of str_cmp, there was not a standard case insensitive library function at the time (I am not even sure if there is now, though most compilers have one like _stricmp).


Is it not strcasecmp now?

I do think that is a name used by some compilers (maybe gcc) I have also seen strcmpi, but stricmp is what the compiler I use for development uses and
the documentation does not list it as ANSI, but it is a bit old (MSVC 6.0). I don't know if strcasecmp is actual ANSI or just a gcc extension.
18 Oct, 2013, Tyche wrote in the 11th comment:
Votes: 0
Nathan said:
That's some pretty strange stuff. Not sure why they're using that pointer arithmetic instead of something more clear. For curiousity's sake does anyone know why they wouldn't have just used normal array access?

It's just programmer preference.

Given char* ch and int i, the following are equivalent:
*(ch + i) == *(i + ch) == ch[i] == i[ch]


Yes the array operator is also commutative! :-)
18 Oct, 2013, Runter wrote in the 12th comment:
Votes: 0
In the 90's I used to see more people writing using the dereference notation. I think it's just probably correctly fallen out of favor.
18 Oct, 2013, quixadhal wrote in the 13th comment:
Votes: 0
The pointer notation can sometimes be more clear, especially if you have strings that you're marching through in parallel. There's also the rare case of accessing raw bytes within larger constructs, but that also involves ugly casting and is not something anyone should ever do. ;)
18 Oct, 2013, Tyche wrote in the 14th comment:
Votes: 0
If you ever used C on MVS or Z/OS, *(ch + i) is preferable to array notation, ch ??( i ??)
But with C99, now we can use the much prettier, ch <: i :>
19 Oct, 2013, Grieffels wrote in the 15th comment:
Votes: 0
Thanks everyone for the assistance everyone. The problem was resolved by going Sharmair's route and finding that check.
As to the camp fire idea, that's something I have already thought about. Camp fires, furnaces and a few other things will accept coal and wood.
I am trying to go the route of (I THINK is the best way) setting a pulse on the object containing coal/wood when coal/wood is ignited. For every
piece of coal, 30 seconds, for every piece of wood, 1 minute. I have also thought about going maybe the AFFECT route and just making it so ignite
gives an affect to objects. If the object has the affect, you're able to smelt, melt, (profession commands), roast (campfire stuff just for the heck of it),
and so forth. What would be the best way, not just the easiest. I want this MUD to really work the way I am seeing everything play out.

Thanks again for the help everyone.
19 Oct, 2013, Vigud wrote in the 16th comment:
Votes: 0
Sharmair said:
At the time it was written some of the C language let alone the run time library were in a state of flux. In at
least some versions of DIKU, there is a commented out strdup function that does exactly what the library function
does
If by "the library" you mean the C standard library as defined by the C standard, then there wasn't and still isn't a strdup() function. It is only standard in UNIX since UNIX 95 and in SVID3.



Sharmair said:
Davion said:
Sharmair said:
But in the case of str_cmp, there was not a standard case insensitive library function at the time (I am not even sure if there is now, though most compilers have one like _stricmp).


Is it not strcasecmp now?

I do think that is a name used by some compilers (maybe gcc) I have also seen strcmpi, but stricmp is what the compiler I use for development uses and
the documentation does not list it as ANSI, but it is a bit old (MSVC 6.0). I don't know if strcasecmp is actual ANSI or just a gcc extension.
strcasecmp() is only standard in UNIX since UNIX 95.

It seems that the authors did not want to depend on UNIX (what later became POSIX) and provided their own functions.
0.0/16