Which makes any coherent discussion of it difficult. You can't really understand the nanny, or grasp the concept behind it, as it's one the most thoughtless pieces of code in ROM. You've probably heard that GOTO is a Bad Thing. Well, the nanny uses 'states' as multiple GOTOs.
If you don't understand switch(), you should probably look it up. Basically, it's a neat way to write a bunch of if, else if, else statements, in the form of 'blocks' identified by 'case', but it requires that all case statements can be identified by the evaluation of first expression in switch. In the nanny, that's the value of d->connected, and d-> connected is reset in most of the 'blocks', which is the equivalent of putting a GOTO everywhere.
It starts when the game asks you for your name, which it then runs through CON_GET_NAME, checking for bad names, then looking to see if the name matches a player file. If it matches a pfile, it loads it, then using the information in the pfile, tests for bans, then sets you to CON_GET_OLD_PASSWORD. Otherwise, it goes to CON_CONFIRM_NEW_NAME, then CON_GET_NEW_PASSWORD, and after it's happy with the pword, it creates a new character.
Roughly, anyway, that's the flow at the top. You'll see that at the end of each action where you're set to a new CON_ state, there's a 'break' or 'return'. These send you back to the top, and you tumble down through until you stop at the matching case and go through the code there.
1) No! Look in comm.c where nanny() is called. I'm pretty sure it's called from the game_loop(). nanny() is only called when d->connected isn't CON_PLAYING, or a couple others (I think involved with either OLC or note writing)
2) If d->connected is something other than one of the 'case' conditions, default will be executed (in an if/elseif/else type statement, default is the 'else')
3) That prints out a new line to a character if the machine your server is running on is unix based. Why… I don't know ;).
1. Right, it only runs when someone is logging in.
2. If the character's CON_ state doesn't match any of the case options, then it sends a bug report to the log, and disconnects the player.
3. This is because the player isn't going to add a newline to his input, and we want one before sending the next message. (Apparently Windows et al would add a newline?)
Note that in most of the ROM code, you're dealing with a 'ch' and using send_to_char() or act() to communicate with them. Since the nanny starts working before they're fully logged in and have a 'ch', it uses 'd' (descriptor) to identify them by the socket they're connected to and writes directly to the output buffer. (for this reason, don't try to send color codes)
I took out all the character creation stuff, and put it in a series of rooms in the game. When you log in to DeepMUD, you choose a name, password, and then splash! You're a zygote, and in the game, able to look around and ask questions on channels.
I suppose I should change the name to something like intercourse(). :redface:
Checking other places out for MudQuest, I found this has become a popular system since I posted "I killed the Nanny!" on the ROM list many years ago. You might consider it, as it's much easier to write creation code using flags to denote states, rather than trying to add more convolutions to a mind-boggling mess.
It's not really all that complicated, you just have to remember that the various connection states don't always map to "game" states. This is also how most muds deal with directing user input to the correct destination function, such as the string editor, or callbacks for answering questions. It's just that MOST dikus only use it for the series of login/creation questions, so that's all anyone ever tries to edit.
Of course, I also agree with Sandi… it's far more interesting to allow character creation to happen in-game.
I think the problem with nanny isn't so much that it implements a state machine (which is after all kind of what it's supposed to be doing) but that it's a huge giant mess lumped into one huge giant function. Just splitting it up into several functions (so that the main one is just a switch statement that immediately defers each state to a function) makes a big difference.