14 Mar, 2009, Igabod wrote in the 1st comment:
Votes: 0
I just released two more snippets for godwars/low4 one is just a replacement for the stock do_score function in LoW4 and the other is actually two functions, beep and nobeep. Beep a person and their computer will play an audible noise that should get their attention if they are in a different window. Nobeep sets the ACT_NOBEEP flag so that you can block incoming beeps.

These are very simple functions and not exactly very original, but I figured I'd release these since low4 is lacking in snippets. I'd like some constructive criticism on both of these snippets and any ideas for improving/fixing them.

Click Me for the do_score replacement snippet.

Click Me for the beep/nobeep snippet.
14 Mar, 2009, Keberus wrote in the 2nd comment:
Votes: 0
Well, you're first issue is that you are sending your telnet all wrong. You are sending IAC IAC, when you should be sending…eh, j/k :). I'm a SMAUG deriv guy myself. But looking over your code I noticed something in the do_nobeep. I don't think you need the arg and one_argument calls because you don't seem to be using the argument anyways.

So I think you could strip out:
char arg[MAX_INPUT_LENGTH];         
one_argument(argument,arg);


For efficiency's sake.

Also, I did notice that in both snippets you used a lot of sprintfs and stc calls. Ever think about using a combined function like SMAUG's ch_printf?


For you it might look something like:
void ch_printf( CHAR_DATA * ch, const char *fmt, … )
{
char buf[MAX_STRING_LENGTH * 2];

va_list args;

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

stc( buf, ch );
}

NOTE: When using a fuction that uses va_list/va_start/va_end you will have to include the header file stdarg.h.


And as for what it would do, here's your original do_beep:
void do_beep(CHAR_DATA *ch, char *argument)
{
CHAR_DATA *victim;
char buf[MAX_STRING_LENGTH];

if(!argument || !(victim = get_char_world(ch,argument)))
{
stc("{cBeep who?{x\r\n",ch);
return;
}

if (IS_NPC(victim))
{
stc("{cYou can only beep players.{x\r\n",ch);
return;
}

if (IS_SET(victim->act,ACT_NOBEEP))
{
sprintf(buf,"{C%s {cis not accepting beeps at this time.{x\r\n",victim->name);
stc(buf,ch);
return;
}
/* If you change the message here, be sure to leave the \a in since it
* is what causes the audible beep.
*/
sprintf(buf,"{C%s {cis beeping you!{x\a\r\n",PERS(ch,victim));
stc(buf,victim);
sprintf(buf,"{cYou beep {C%s.{x\r\n",PERS(victim,ch));
stc(buf,ch);
return;
}


And here's the slightly more simplified version with ch_printf being used:
void do_beep(CHAR_DATA *ch, char *argument)
{
CHAR_DATA *victim;

if(!argument || !(victim = get_char_world(ch,argument)))
{
stc("{cBeep who?{x\r\n",ch);
return;
}

if (IS_NPC(victim))
{
stc("{cYou can only beep players.{x\r\n",ch);
return;
}

if (IS_SET(victim->act,ACT_NOBEEP))
{
ch_printf( ch, "{C%s {cis not accepting beeps at this time.{x\r\n",victim->name);
return;
}
/* If you change the message here, be sure to leave the \a in since it
* is what causes the audible beep.
*/
ch_printf( ch,"{C%s {cis beeping you!{x\a\r\n",PERS(ch,victim));
ch_printf( ch,"{cYou beep {C%s.{x\r\n",PERS(victim,ch));
return;
}


I know, it just shaves off a few lines of code, but I like any functions that can do that.

Later,
KeB
14 Mar, 2009, Igabod wrote in the 3rd comment:
Votes: 0
You're right about the arg and one_argument thing. That's what happens when I just do a quick edit of a snippet so that it works for a different codebase.

Funny thing is that is from a smaug snippet and it isn't using ch_printf. I would do it that way but that would make the snippet a little more complex since it's designed for low4 which doesn't have ch_printf already. I like to try to keep my snippets simple when they are for something as simple as this.

I will however do that on my personal mud, thank you for the suggestion. I've been thinking about doing that for a little while now and just didn't have the motivation. Anyway, the two lines in nobeep that are useless have been removed. Thanks Keberus, and thanks to anybody else that has any suggestions.
14 Mar, 2009, Kline wrote in the 4th comment:
Votes: 0
Sorry, unrelated to your snippets: does ch_printf catch formatting errors, like trying to cram an int into a string ala snprintf(buf,size,"%s",5) ? The last time I used any kind of wrapper around sprintf/snprintf it wasn't capable of catching things like that, so I'd segfault or notice something odd in game and have to go hunt it down later.
14 Mar, 2009, elanthis wrote in the 5th comment:
Votes: 0
The function itself is totally and completely incapable of checking for that. Those kind of type-checking features are special tricks built-in to the compiler, not the library.

If you're using GCC as your compiler, you are in luck, because you can ask the compiler to apply that type checking to any function. by using something like the following in the header with the function's declaration:

extern int ch_printf (CHAR_DATA *ch, const char *my_format, …)  __attribute__ ((format (printf, 2, 3)));


The format attribute's parameters are the position of the format string (2nd ch_printf parameter in this case) and the position of the start of the format data (which is the 2rd ch_printf parameter, the ellipsis).

Pretty handy if you're ever making your own printf wrappers. You can put the attribute into a macro and only define it when compiling under GCC to make it safer:

#ifdef __GNUC__
# define GNUC_FORMAT(fmt,args) __attribute__ ((format (printf, fmt, args)))
#else
# define GNUC_FORMAT(fmt,args)
#endif

extern int ch_printf (CHAR_DATA *ch, const char *my_format, …) GNUC_FORMAT(2, 3);
14 Mar, 2009, Keberus wrote in the 6th comment:
Votes: 0
So that stuff only works with gcc and not g++?
14 Mar, 2009, David Haley wrote in the 7th comment:
Votes: 0
I think it works with g++ too. Generally speaking g++ doesn't take features away from gcc.
14 Mar, 2009, Fizban wrote in the 8th comment:
Votes: 0
David Haley said:
I think it works with g++ too. Generally speaking g++ doesn't take features away from gcc.


Aye, g++, gcc, gdc, and all of the other existing compilers that are created by the same team have the same features, they're just are aimed at different languages.

The exact error gcc sends is (I intentionally removed a %s in a line and replaced it with a %d error for testing purposes): act.informative.c:80: warning: int format, pointer arg (arg 3)
14 Mar, 2009, Kline wrote in the 9th comment:
Votes: 0
Awesome, thanks elanthis, didn't ever know about __attribute__. Now happily using ch_printf with checking :)
14 Mar, 2009, Lobotomy wrote in the 10th comment:
Votes: 0
Kline said:
Awesome, thanks elanthis, didn't ever know about __attribute__. Now happily using ch_printf with checking :)

As a side note, if you want to find out about other attributes you can use with GCC there's a page for function attributes, variable attributes, and type attributes.
14 Mar, 2009, elanthis wrote in the 11th comment:
Votes: 0
Other compilers usually support those attributes too. The __attribute__ syntax is standardized in C99 (I think – I know it is in C++0x), but I believe the format attribute specifically is a GCC extension. However many compilers support GCC extensions, especially compilers intended for UNIX extensions. I'm fairly sure ICC, SunC, and Clang all support the format thing. You may need to replace the #ifdef __GNUC__ with an #if defined(__GNUC__) || defined(__SUN__) etc. (not sure on the specifics – I'm stayinig a C compiler monogamist until Clang becomes stable).
14 Mar, 2009, Keberus wrote in the 12th comment:
Votes: 0
I gotta say, the __attribute__ syntax is a pretty awesome trick. Thanks for the info Elanthis, and thanks for the other info as well Labotomy.
0.0/12