07 Sep, 2008, Valcados wrote in the 1st comment:
Votes: 0
Hello :unclesam:

I just finished writing a birds-eye walkthrough of the SMAUG codebase and how it works.

It's focused on broad generalities and my aim is to give a sense of the bigger patterns which govern the SMAUG universe.

I *guarantee* if you haven't been coding for at least five years, reading this document WILL make you a better coder!

It would probably be useful reading for anyone who works in any branch of Diku, since the fundamental structure of the codebase hasn't changed that much over the years, only the details.

Check it out at my SMAUG Snippets and Tippets site. It's a brand new site and I'd love feedback on it :redface:
08 Sep, 2008, Caius wrote in the 2nd comment:
Votes: 0
Valcados said:
I *guarantee* if you haven't been coding for at least five years, reading this document WILL make you a better coder!

That's a pretty bold statement.
08 Sep, 2008, Vladaar wrote in the 3rd comment:
Votes: 0
Great Job Valcados,

I assume your just explaining theory more then teaching coding on that site.

Would be cool if someone combined the theory of smaug coding with Gangien's tutorial, gdb tutorial, valgrind tutorial, etc.
Well the articles on mudbytes would prob work.

here' is Gangiens tutorial I found on internet archive since his site is down

SMAUG Coding Tutorial
By Gangien (gangien@hotmail.com)
Homepage http://dod.hpi.net/gangien

Introduction

This tutorial is intended for those who have some familiarity with C or at the very least programming experience. I have been coding on a mud for the past 5+ years so I think I know a thing or two, though I'm sure there's lots about SMAUG I have yet to learn. Though this will be centered on coding for a SMAUG mud, it can probably be applied to any mud, but the functions and code samples will probably not work without a little bit of modification. If someone would like to 'port' my tutorial to another code base, I'll gladly post it here.

What this is not, this is not a learn C tutorial. I assume that you have a basic understanding of C. I will explain pointers a little bit since they seem to confuse people, but beyond that, I'll assume you know how to use C. This is also not a guide for installing SMAUG or other code bases, or how to compile them. I assume that you have a working copy of SMAUG and that you know how to compile it.

If you wish to post this tutorial someplace else, I hope that you will at least email me. I have no problems with it being anywhere else, as long as the credit for me writing it is kept, and my email/homepage address is kept.

Making Your own Command

One of the most basic things you can do with a mud, coding wise, is create a new command. So what we're going to do is to create a simple command that will send the character some output. So open up a file, (recremmended file: player.c) and go to the end of it, or In between some functions that make sense and type this line:

void do_showstats(CHAR_DATA *ch, char *argument)
{
ch_printf(ch, "Str: %d\tDex: %d\tWis: %d\tInt: %d\n\r",
get_curr_str(ch), get_curr_dex(ch),
get_curr_wis(ch), get_curr_int(ch));

ch_printf(ch, "Cha: %d\tCon: %d\tLck: %d\n\r",
get_curr_cha(ch), get_curr_con(ch),
get_curr_lck(ch));
return;
}

ch is a pointer to the CHAR_DATA of the user who typed the command, and argument is a pointer to the string that was typed after the command, and before the user hit enter. We'll get into how to parse the argument pointer later.

The ch_printf function, prints the text to the character. similar to fprintf and printf, excelt it requires a CHAR_DATA pointer as the first parameter. The functions get_curr_str, and the others, are functions that can be found in handler.c. They return the current strength, and other attributes of the player. So a player with all attributes at 18, would have the following displayed if he entered the command.

Str: 18 Dex: 18 Wis: 18 Int: 18
Cha: 18 Con: 18 Lck: 18

If you wish to spice things up a bit (add color) use the ch_printf_color function instead, it has the same parameters as ch_printf.

Now then, we must make 3 more additions to the code base, before we recompile. The first is to mud.h. Do a search for do_showrace and you'll see a line like this: DECLARE_DO_FUN(do_showrace); As you've probably guessed, we need to add a line like that, ECLARE_DO_FUN(do_showstats);

Now edit tables.c and again search for do_show race, and again make a new line similar to the last

if ( !str_cmp( name, "do_showstats" )) return do_showstats;

Then further down the file (do another search) make another addition

if ( skill == do_showstats ) return "do_showstats";

Now, make clean and recompile, there shouldn't be any problems, and reboot the mud. Now the command is in the code base, but SMAUG doesn't know that yet, so you have to tell it where to look for it, so you have to give the following commands

cedit showstats create do_showstats
cedit save cmdtable

There are other commands you can give, like the level, but you'll have to look them up on your own. Now then, type the command showstats and you should see two lines that list your stats. And there you have it your first command.

Getting Input from a command

Getting input from a command is very easy, since a string pointer is passed through all do_functions. But let's go back to that command we just made, do_showstats, at the beging add the lines

char arg[MAX_INPUT_LENGTH];

argument = one_argument(argument, arg);

If you say that last line out loud you may sound like a pirate to those around (stupid joke). Now you should know what the first line is, MAX_INPUT_LENGTH is in mud.h. but the second line, is similar to ones you'll see all throughout the code. What it does is it takes the string, argument, takes out the next word, puts that word into the arg pointer, and returns a pointer to the next word in the argument function. For example (cus I know I rambled there a bit)

argument = "this is fun", you pass this through that function and this is what you get in return.

argument = "is fun"
arg = "this"

one_argument will also parse anything inside quotes as a word and ignore leading white space so if
argument = " 'this is fun' yeah!"

after you pass it through one_argument
arg = "this is fun"
argument = "yeah!"

Now add the following code after the one_argument call

if(!str_cmp(arg, "str") {
send_to_char("You only asked for strength.\n\r", ch);
ch_printf(ch, "Str: %d\n\r", get_curr_str(ch));
return;
}

The str_cmp function, is similar to the ANSI C function strcmp, except str_cmp ignores case, so "This" == "tHIS".
The send_to_char function, takes a string pointer, and a CHAR_DATA pointer as parameters, and will show the character the string. Recompile and reboot. Now if you type showstats str, it will show this:

You only asked for strength.
Str: 18

If you noticed, the one_argument function, isn't really necessary here, since the original argument pointer already points to the first word. But I thought I'd add it in for practice.

Now your command looks like almost every other command in the SMAUG code, though somewhat smaller.

Say you want to make it so that only players (not mobs) halfway to avatar or under and immortals, to be able to use this command. You would add this code, to preferable just after the declartion of variables.

if(IS_NPC(ch)) {
send_to_char("Mobs may not use this command.\n\r", ch);
return;
}

if(get_trust(ch) > LEVEL_AVATAR / 2 && !IS_IMMORTAL(ch)) {
send_to_char("Cannot be more than halfway to avatar to use this command.\n\r", ch);
return;
}

You are probably thinking these are some very stupid restrictions to a piece of code. And you're right, but that's not the point. The first check should be obvious once you look at it. It checks if the character is an NPC, and returns TRUE if it is. This can be very important in some commands. if you have a command that accesses pcdata, like channels for instance, You must return before that data is accessed, otherwise the mud will crash, because mobs don't have pcdata. Because of the trust attribute that a person can have, I usually use it instead of ch->level. Although since mortals probably don't have a trust, You could put ch->level instead of get-Trust. But get_trust returns ch->level if there is no trust. The IS_IMMORTAL check should, like IS_NPC, be obvious, it returns TRUE if the player is an immortal. So basically if you typed in the command on a stock mud you would have to meet the following requirements:

Be level 25 or less, or be level 101 or more And you would have to be a character, so if you ordered a MOB to do it, it wouldn't work.

Getting Objects, Mobs and PCs from a string

Creating a command, you'll often times need to find a char with the input string. This is easy enough. Say you wish to create a glory transfer command (It was the first command I ever made :) with a syntax of glorytransfer <victim> <amount> so You'll have to get the second argument as the 'victim'. All the SMAUG code using the victim as the target of the code, so it's probably best to keep that consistent. So first you'll need to parse the string into two variables.

char arg[MAX_INPUT_LENGTH];
argument = one_argument(argument, arg);

Now you have arg, being the name of the victim, and argument being the amount in a string. Now for clarity, you might make an arg2 or something and have that be the amount (have a second one_argument call), but you don't need too. Now there are two functions that you can use here, get_char_world and get_char_room, I think their names make them obvious of how to use them. They both have the same parameters as well and both return the resulting CHAR_DATA pointer, if a victim is found. So let's add some more code:

if(((victim = get_char_room(ch, arg)) == NULL) {
send_to_char("That character is not in this room.\n\r", ch);
return;
}

and there we have it, now victim is pointing to the correct player and you can use it however you like. You'd probably make another int, and assign it atoi(argument) then add the glory and take away the glory from the ch. Also these functions work for mobs and PC's alike.

For objects, it's very similar, here are the function prototypes, you should be able to understand what they mean. They use the exact same parameters as the get_char functions, (except they return type OBJ_DATA *)

OBJ_DATA * get_obj_carry args( ( CHAR_DATA *ch, char *argument ) );
OBJ_DATA * get_obj_wear args( ( CHAR_DATA *ch, char *argument ) );
OBJ_DATA * get_obj_here args( ( CHAR_DATA *ch, char *argument ) );
OBJ_DATA * get_obj_world args( ( CHAR_DATA *ch, char *argument ) );

The one exception is
OBJ_DATA * get_obj_vnum args( ( CHAR_DATA *ch, int vnum ) );

which obviously you have to pass the vnum in an integer, instead of searching for it by name.

Using Other do_functions

Say you want to add a command, like a glory purchase command, and you want to add a bit of rp to it. You could make the mobile that does 'enchanting of items' do emotes, or do says, or you could use the act function to make it seem like he's saying things. Personally, I like to use other functions, to keep things consistent, IE if you decide to change the color of say someday, but your code uses what it used to be, then it would look weird. so you could create a command like enchant <item>, first things first you would have to check if the proper mobile is in the room, you should be able to figure out a way to do that by now. And you need to check if the item is in the character's inventory. So if it's all good, then you could use the do_give and do_say functions to make it look more realistic. And you could also check to see if the character can hold the item again, if he can't you could just drop it and say something like you can't hold it or whatever. Anyhow the main point of this section is to point out you can use the other do functions, like in the glorytranfer command, if the player enters the wrong set of strings you could have do_help(ch, "glorytranfers");

Pointers

Because of the intended audience, I'm going to take a moment and attempt to explain pointers. Pointers are wonderful, I love them, I hate java because it doesn't have pointers (among other reasons). They also can be confusing if you've never used them, or if you come from a background of Qbasic or Visual Basic type programming. This is basically how pointers work.

You define an integer by using int x; now say you have a function that you want it to have some parameters that you want to modify their values. Pointers work perfectly in this case (unless your using C++ and can pass by value but I'm assuming not). So say you want a function that tells the level range of a pkiller. So you create the function

void get_range(CHAR_DATA *ch, int *low, int *high)
{
*low = ch->level - 5;
*high = ch->level + 5;
if(*low < 5) *low = 5;
if(*high > LEVEL_AVATAR) *high = LEVEL_AVATAR;
return;
}

Now all you have to do is, pass the address of two integers and the CHAR_DATA, which is already refered to by a pointer, and those intengers will then have the values aassigned to them in the get_range function. Example:

int lo, hi;
get_range(ch, &lo, &hi)l

Now lo has the low level, and hi has the high level. But you may be asking what do all those things represent. Here's what they do in a nutshell. int *x; defines a pointer, x, to a type integer. So the parameters in the function get_range are expecting two pointers to integers. The way to access the address of a non pointer, is to use the & operand. So if you have int x, to access it's pointer you do &x, like I did in the example above.

Strings in C are also pointers, for instance in the functions that you used ch_printf, and then a string, it's really just a pointer to a char type. String must end with a '\0' or null bit (The end of a literal string like "test" automatically have a terminating null bit).

Arrays are also a series of pointers. Basically say you have int array[10]; *array is the same as array[0]; and you can do pointer arithmetic, which I won't go into detail about. Anyhow I hope that clarifies some things, here's some code to think about, if you understand it, you understand pointers :)

char buf[100], buf2[100]; char *ptr1 = buf, *ptr2 = buf2;
while(*(ptr1++)=*(ptr2++));

What this does is copy the contents of buf2 into buf. I'd strongly recremmend learning pointers from a real source though, like a book or website tutorial or something, because they can be handy, useful and they are used all throughout the code, though you could get along without understanding them, it would help. From here on in, it is assumed that you understand pointers.

Memory Functions

SMAUG has a nice amount of wrappers that allow for easy creation of stuff. For example if you want to create a new obj, you would do like this:

OBJ_DATA *obj;
CREATE(obj, OBJ_DATA, 1);

nice and simple right? now you've got a new obj that's been allocated and is free to edit. I'm going to run down a list of wrappers/functions that is included in SMAUG and try to explain them

CREATE( pointer, data_type, amount) - allocates memory for data_type and assigns pointer the address of the memory it creates

LINK (node, first_node, last_node, next, prev); will insert node in the doubly linked list, at the end of it.

UNLINK(node, first_node, last_node, next, prev); will remove node from the doubly linked list it's in.

INSERT(node, node_before, first_node, next, prev); will insert node, before node_before in a doubly linked list.

DISPOSE(pointer); frees pointer that was created with CREATE

Here comes the fun part hashed/unhashed strings. If you don't understand what hashing is, let's just say it's a way to improve the speed of finding things. For instance if you have a linked list, and you want to find something you may have to go through the whole list, or the first item, so your average amount is number of linked lists / 2. Hast improves this by using ways of 'sorting' the list, so when you search for a string, it has to go through less to find the string. Although the worst and best case scenarios are the same as a linked list, the average time it takes to find it, is much less.

QUICKLINK: increments the internal usage counter for a hashed string and
returns a pointer to said string

STRALLOC: duplicates a string. searches the string hash table for the
string, and if it exists, performs the equivalent of a QUICKLINK. if it
doesn't exist, it adds it to the hash table and returns a pointer to the
new (hashed) copy of the string. can use this on either hashed or
unhashed strings, but it returns a hashed string.

STRFREE: frees a hashed string.

QUICKMATCH: compares two hashed strings ("quickly") by comparing their
memory addresses. it wont crash you if you use it on an unhashed string, but it will always return false. (hashed strings share memory which is why this works for them, and the whole purpose of hashing in the first place really)

fread_string: reads a tilde-terminated(~) string from a file, hashes it,
and returns a pointer to the string

str_dup: duplicates a string. can be used on either hashed or unhashed,
but returns an unhashed string.

fread_string_nohash: does the same as fread_string, but the string doesn't get hashed.

Altrag was the one who wrote those explanations of the functions, you can find the email in the SMAUG Mailing list archives.

It is important to know whether a string is hashed or not, because if you used the wrong functions, you can end up with problems, and I know this first hand.

Lists

One of the things SMAUG has done, is most structs are in a doubly linked list. So you can traverse lists with ease. For example if you wanted to send to every character (mobs included) some text, you would have a loop like this:

for(rch = first_char; rch; rch = rch->next)
ch_printf(ch, "%s\n\r", txt_pointer);

You could also traverse through all the areas in the game:

for(area = first_area; area; area = area->next);

The same holds true of just about anything that comes in stock SMAUG. Now if you want to display a message to all the characters, you could use the code above and add if(IS_NPC(rch)) continue; but a more practical, faster, way of doing that, is going through the descriptors.

DESCRIPTOR_DATA *d;
for(d=first_descriptor; d; d = d->next) {
if(!CH(d)) continue;
send_to_ch_printf(CH(d), "%s\n\r". argument) ;
}

The CH is just a define that points to d->character or d->original.

Bit Vectors

SMAUG has a nice implementation of bit vectors, that can be very useful. Don't know what a bit vector is? well think of it this way, it's a bunch of Booleans. Let me explain. Since, data is stored in binary form, there are 32 bits that make up an integer type. That means that there basically 32 on/off, true/false variables inside an int, if you use it correctly. Making the functions to do all this stuff, isn't hard, but why do that, when they are already there. Here are the functions

IS_SET(int, bit)
TOGGLE_BIT(int, bit)
SET_BIT(int, bit)
REMOVE_BIT(int, bit)

now this may not look useful, but let's see what it can do. Say you wish to add a flag to players, that this player would be unable to be seen All you would have to do is, go into mud.h, at the end of all the PCFLAGS, add a new one, then check for it wherever you set the flag, or need to check if the flag is there. So you might add a new command, to do the following

TOGGLE_BIT(victim->pcdata->flags, PCFLAG_VISABLE)

then in the can_see function, if(IS_SET(victim, PCFLAG_VISABLE)).
You don't have to add another Boolean to the char data, and bloat the pfile up even more, it's all automatically handled through these bitvectors. Of coruse if you want to create a new bitvector, then you have to write it to the pfile, but that's just like writing and reading and integer type, so it's no big deal.

Say you want to add an arena, that has some of the flags like, noflee, noheal, nowait ect.. So you set up an arena struct and add it in a similar way that sysdata is setup. You'll need to add (if you want to keep consistent with the SMAUG way of doing things) 2 dimensiolnalarray of strings like

char * const arena_flags [] = { "noheal", "nowait", "noflee" };
and add some defines for the flags in mud.h

#define ARENAFLAG_NOHEAL BV00
#define ARENAFLAG_NOWAIT BV01
#define ARENAFLAG_NOFLEE BV02

You already know how to toggle bits, but here it gets a bit more complicated. You want a command to set the arena with certain flags, so how do you display all the flags, in a readable fashion, and how to you take an input line and get the flags out of that? Well the answer to the latter is easy, since SMAUG comes with a function to do that.

ch_printf(ch, "Flags: %s\n\r", flag_string(arena.flags, arena_flags));

this line, takes the bitvector, arena.flags and the strings that it represents, arena_flags, and parses them. Now to make this work, the first #define must relate to the first string in the area_flags array.

Now, how do you parse an input line that has a list of flags, like mset does. It's a bit more complicated, but still not all that hard.

char arg[MAX_INPUT_LENGTH];

while ( argument[0] != '\0' ) {
int value;
argument = one_argument( argument, arg );

value = get_arenaflag( arg );
if ( value < 0 || value > MAX_BITS )
ch_printf( ch, "Unknown flag: %s\n\r", arg3 );
else
TOGGLE_BIT( arena.flags, 1 << value );
}
send_to_char("Ok.\n\r", ch);
return;
}

The only thing that shouldn't make sense (unless you don't understand bit manipulation) is the get_arenaflag, function. Well we haven't quite made that yet, so let's do that now.

int get_arenaflag( char *flag )
{

int x;

for ( x = 0; x < (sizeof(arena_flags) / sizeof(arena_flags[0])); x++ )
if ( !str_cmp(flag, arena_flags[x]) )
return x;
return -1;
}

Say you put the snippet of code that parses the user input, you could do like this:

arena flags noheal nowait noflee

and that would toggle all those flags, which you could then check for accordingly.
08 Sep, 2008, David Haley wrote in the 4th comment:
Votes: 0
Some first impressions:

- I think it might be better to be slightly more modest. Whether or not it's true, it's a little off-putting to see continual claims of outstanding performance. If you're going to make big claims about yourself, it should be clear to the unfamiliar reader why you have the right to do so. Actually, the reasons should be sufficient for the reader to infer on their own that you could make those claims if you wanted to.

- Your guide uses rather absolute terms like "I outline exactly how SMAUG actually works". That's a pretty big thing to say, especially considering that you gave a very high-level overview.

- As a matter of personal preference, I think that something can be simple and straightforward without being overly colloquial or abusing fake reader questions.

- I think the bit about guaranteeing that people will be better coders if they've been coding for less than 5 years is a little bold, to not say a completely excessive thing to say. The guide doesn't even really go into that much programming detail at all so I'm not sure why it would improve the skills of somebody who's been working with SMAUG for even just a bit. You also might not have wanted to use the term "coder" in general. It might be more reasonable to say that your guide will improve the understanding somebody has of the general architecture. Even then, you don't really describe the algorithms or data structures that much.

- I think it's a bad idea to call the main loop an "almost-infinite loop". I think that is pretty misleading: really, it's not "almost infinite" at all, it is extremely clear when the loop terminates.


These are just very first impressions since I'm in something of a hurry. I think the guide has a lot of potential and can be/is very useful. I'm sharing these only because I would not want somebody to ignore the guide because they found the above to be turn-offs as well.
08 Sep, 2008, David Haley wrote in the 5th comment:
Votes: 0
Gangien's guide said:
I hate java because it doesn't have pointers

That's a kind of silly thing to say, since every variable in the entire language except for primitives (int, boolean, double, float, etc.) are pointers… I'm hoping there is more to this statement than just the above. Sounds like somebody who hates Java without having written much code with it.
08 Sep, 2008, Valcados wrote in the 6th comment:
Votes: 0
Wow, thanks a lot Vladaar! I hope Gangien's site comes back online, cuz I'd like to link to that article from mine!

Yes, my article is more theoretical. It implicitly assumes a greater background than Gangien, but at the same time, it doesn't actually require any knowledge of C at all, so it could be read by someone with absolutely no programming experience and they'd still gain insight just as a player. Kind of like Feynman's laymens guide to physics, except the physics of SMAUG instead of real life.

Caius: yes, I realize I made a bold statement, and I guess you could be the exception. The thing is though, the article includes some things that I didn't figure out for almost a decade of coding, despite being very prolific. And I think it's the first article of its kind, to explain the bigger picture of how SMAUG works.

I've looked at a lot of SMAUG code snippets, and there are certain "taboos" that noone seems to want to violate. For example, doing things between the pulses. The infinite loop in game_loop is called X times a second (X=4?), but with modern computers, that leaves soooooo much spare time between pulses. You could literally run a 2nd MUD just between those pulses, listening on a separate port, etc. The possibilities are pretty endless. But it seems like that is considered "sacred ground" in the community, and no coders are willing to touch it. Well, I think my document helps open the way, just by making people aware that it's there.

From what I've seen, very few coders outside the SMAUG team can boast deep surgical changes to the core of the game. With some exceptions like Senir's housing or Rasmus's mpsleep or overworld support, most snippets only significantly change things at a "skin deep" level. By "skin deep", I mean stuff which is 3 or more function calls removed from main. You can think of main as "level 0" (0 steps away), "game_loop" as level 1 (1 step away), interpret as level 2, and then you have actual skills/commands/etc. which are level 3. Level 3 and above is where almost all code changes are made. And I think in part that's just because that's what most coders understand.

Anyway, hope you gain something from the article even if you are super advanced. I wrote it for everyone :unclesam:
08 Sep, 2008, Valcados wrote in the 7th comment:
Votes: 0
DavidHaley said:
Some first impressions:

- I think it might be better to be slightly more modest. Whether or not it's true, it's a little off-putting to see continual claims of outstanding performance. If you're going to make big claims about yourself, it should be clear to the unfamiliar reader why you have the right to do so. Actually, the reasons should be sufficient for the reader to infer on their own that you could make those claims if you wanted to.

- Your guide uses rather absolute terms like "I outline exactly how SMAUG actually works". That's a pretty big thing to say, especially considering that you gave a very high-level overview.

- As a matter of personal preference, I think that something can be simple and straightforward without being overly colloquial or abusing fake reader questions.

- I think the bit about guaranteeing that people will be better coders if they've been coding for less than 5 years is a little bold, to not say a completely excessive thing to say. The guide doesn't even really go into that much programming detail at all so I'm not sure why it would improve the skills of somebody who's been working with SMAUG for even just a bit. You also might not have wanted to use the term "coder" in general. It might be more reasonable to say that your guide will improve the understanding somebody has of the general architecture. Even then, you don't really describe the algorithms or data structures that much.

- I think it's a bad idea to call the main loop an "almost-infinite loop". I think that is pretty misleading: really, it's not "almost infinite" at all, it is extremely clear when the loop terminates.


These are just very first impressions since I'm in something of a hurry. I think the guide has a lot of potential and can be/is very useful. I'm sharing these only because I would not want somebody to ignore the guide because they found the above to be turn-offs as well.
David, thanks, I know you're a very skilled coder so I appreciate your feedback. Maybe I will tone it down a little, then. Hmm
08 Sep, 2008, Valcados wrote in the 8th comment:
Votes: 0
By the way, what would be a better way to speak of a loop which is technically not infinite, but, for lack of human intervention or a scheduled reboot, is effectively infinite? I chose "infinite" loop with the quotes, because I didn't want to have to type out a long explanation, or use an obscure programming term, every time I referred to that particular while loop.
08 Sep, 2008, David Haley wrote in the 9th comment:
Votes: 0
That's a good question, really. I'm not sure you need to call it anything other than just "main game loop". Even putting the word "infinite" in there makes me uneasy because it's not, it's just as you said, without something happening it'll keep on going. And sorry if I came off strong, it wasn't my intention, I was just kind of in a hurry. Sorry! :redface:
08 Sep, 2008, Lobotomy wrote in the 10th comment:
Votes: 0
Conditional loop may be what you're looking for. Although, I think calling it an infinite loop is equally as valid when the infinity is a desired aspect of the loop; i.e, when creating a game loop that should loop endlessly until told to stop.
08 Sep, 2008, David Haley wrote in the 11th comment:
Votes: 0
An infinite loop has a very specific meaning, and this isn't it. :wink: If it were actually impossible to quit the loop (and yes, that can be desirable) it would be an infinite loop, but this loop really is not infinite.
08 Sep, 2008, Guest wrote in the 12th comment:
Votes: 0
Valcados said:
From what I've seen, very few coders outside the SMAUG team can boast deep surgical changes to the core of the game. With some exceptions like Senir's housing or Rasmus's mpsleep or overworld support, most snippets only significantly change things at a "skin deep" level.


Bah, I don't get mentioned by name for the overland code? :cry:

And I've looked at the housing code before. I'm not really sure I'd consider that a "deep surgical change" to the code. mpsleep is a bit closer to that definition, even though all it touches is mudprogs. Surely the three things you mentioned aren't the only deep rooted changes that have been made?
08 Sep, 2008, Kayle wrote in the 13th comment:
Votes: 0
*cough* Weather System *cough*

[Edit:] Noticed this as it came across inews, Since this is a SMAUG guide, shouldn't it be in the Uh… SMAUG forum?
08 Sep, 2008, Valcados wrote in the 14th comment:
Votes: 0
Thanks a lot for the feedback, guys. I changed the main page to remove the guarantee and make it softer. And made a note about the "infinite" loop so as not to confuse anyone. Looks like I can't edit the post here though.
08 Sep, 2008, Fizban wrote in the 15th comment:
Votes: 0
Vladaar said:
Would be cool if someone combined the theory of smaug coding with Gangien's tutorial, gdb tutorial, valgrind tutorial, etc.
Well the articles on mudbytes would prob work.


Interesting, I'd never seen that, which shocks me. Gangien was the head coder of the first mud I ever played in the late 90's. The mud still runs but is all 'but' dead.

Vladaar said:
here' is Gangiens tutorial I found on internet archive since his site is down


The game moved domains a few years back, the site is now located here.
0.0/15