24 Dec, 2015, thecircuitbox wrote in the 1st comment:
Votes: 0
/* deal with newcomers and other non-playing sockets */ void nanny(struct descriptor_data *d, char *arg) { int load_result; /* Overloaded variable */ int player_i;
/* Quick check for the OLC states. */ for (player_i = 0; olc_functions[player_i].state >= 0; player_i++) if (STATE(d) == olc_functions[player_i].state) { (*olc_functions[player_i].func)(d, arg); return; }
/* Not in OLC. */ switch (STATE(d)) { case CON_GET_PROTOCOL: write_to_output(d, "Collecting Protocol Information… Please Wait.\r\n"); return; break; case CON_GET_NAME: /* wait for input of name */ if (d->character == NULL) { CREATE(d->character, struct char_data, 1); clear_char(d->character); CREATE(d->character->player_specials, struct player_special_data, 1);
if (PLR_FLAGGED(d->character, PLR_DELETED)) { /* Make sure old files are removed so the new player doesn't get the * deleted player's equipment. */ if ((player_i = get_ptable_by_name(tmp_name)) >= 0) remove_player(player_i);
/* We get a false positive from the original deleted character. */ free_char(d->character);
if (GET_HOST(d->character)) free(GET_HOST(d->character)); GET_HOST(d->character) = strdup(d->host);
d->character->desc = d; CREATE(d->character->player.name, char, strlen(tmp_name) + 1); strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */ GET_PFILEPOS(d->character) = player_i; write_to_output(d, "Did I get that right, %s (\t(Y\t)/\t(N\t))? ", tmp_name); STATE(d) = CON_NAME_CNFRM; } else { /* undo it just in case they are set */ REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING); REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING); REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_CRYO); d->character->player.time.logon = time(0); write_to_output(d, "Password: "); echo_off(d); d->idle_tics = 0; STATE(d) = CON_PASSWORD; } } else { /* player unknown – make new character */
/* Check for multiple creations of a character. */ if (!valid_name(tmp_name)) { write_to_output(d, "Invalid name, please try another.\r\nName: "); return; } CREATE(d->character->player.name, char, strlen(tmp_name) + 1); strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
write_to_output(d, "Did I get that right, %s (\t(Y\t)/\t(N\t))? ", tmp_name); STATE(d) = CON_NAME_CNFRM; } } break;
case CON_NAME_CNFRM: /* wait for conf. of new name */ if (UPPER(*arg) == 'Y') { if (isbanned(d->host) >= BAN_NEW) { mudlog(NRM, LVL_GOD, TRUE, "Request for new char %s denied from [%s] (siteban)", GET_PC_NAME(d->character), d->host); write_to_output(d, "Sorry, new characters are not allowed from your site!\r\n"); STATE(d) = CON_CLOSE; return; } if (circle_restrict) { write_to_output(d, "Sorry, new players can't be created at the moment.\r\n"); mudlog(NRM, LVL_GOD, TRUE, "Request for new char %s denied from [%s] (wizlock)", GET_PC_NAME(d->character), d->host); STATE(d) = CON_CLOSE; return; } perform_new_char_dupe_check(d); write_to_output(d, "New character.\r\nGive me a password for %s: ", GET_PC_NAME(d->character)); echo_off(d); STATE(d) = CON_NEWPASSWD; } else if (*arg == 'n' || *arg == 'N') { write_to_output(d, "Okay, what IS it, then? "); free(d->character->player.name); d->character->player.name = NULL; STATE(d) = CON_GET_NAME; } else write_to_output(d, "Please type Yes or No: "); break;
case CON_PASSWORD: /* get pwd for known player */ /* To really prevent duping correctly, the player's record should be reloaded * from disk at this point (after the password has been typed). However I'm * afraid that trying to load a character over an already loaded character is * going to cause some problem down the road that I can't see at the moment. * So to compensate, I'm going to (1) add a 15 or 20-second time limit for * entering a password, and (2) re-add the code to cut off duplicates when a * player quits. JE 6 Feb 96 */
echo_on(d); /* turn echo back on */
/* New echo_on() eats the return on telnet. Extra space better than none. */ write_to_output(d, "\r\n");
if (isbanned(d->host) == BAN_SELECT && !PLR_FLAGGED(d->character, PLR_SITEOK)) { write_to_output(d, "Sorry, this char has not been cleared for login from your site!\r\n"); STATE(d) = CON_CLOSE; mudlog(NRM, LVL_GOD, TRUE, "Connection attempt for %s denied from %s", GET_NAME(d->character), d->host); return; } if (GET_LEVEL(d->character) < circle_restrict) { write_to_output(d, "The game is temporarily restricted.. try again later.\r\n"); STATE(d) = CON_CLOSE; mudlog(NRM, LVL_GOD, TRUE, "Request for login denied for %s [%s] (wizlock)", GET_NAME(d->character), d->host); return; } /* check and make sure no other copies of this player are logged in */ if (perform_dupe_check(d)) return;
if (GET_INVIS_LEV(d->character)) mudlog(BRF, MAX(LVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "%s has connected. (invis %d)", GET_NAME(d->character), GET_INVIS_LEV(d->character)); else mudlog(BRF, LVL_IMMORT, TRUE, "%s has connected.", GET_NAME(d->character));
/* Add to the list of 'recent' players (since last reboot) */ if (AddRecentPlayer(GET_NAME(d->character), d->host, FALSE, FALSE) == FALSE) { mudlog(BRF, MAX(LVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "Failure to AddRecentPlayer (returned FALSE)."); }
case CON_CNFPASSWD: case CON_CHPWD_VRFY: if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) { write_to_output(d, "\r\nPasswords don't match… start over.\r\nPassword: "); if (STATE(d) == CON_CNFPASSWD) STATE(d) = CON_NEWPASSWD; else STATE(d) = CON_CHPWD_GETNEW; return; } echo_on(d);
if (STATE(d) == CON_CNFPASSWD) { write_to_output(d, "\r\nWhat is your sex (\t(M\t)/\t(F\t))? "); STATE(d) = CON_QSEX; } else { save_char(d->character); write_to_output(d, "\r\nDone.\r\n%s", CONFIG_MENU); STATE(d) = CON_MENU; } break;
case CON_QSEX: /* query sex of new user */ switch (*arg) { case 'm': case 'M': d->character->player.sex = SEX_MALE; break; case 'f': case 'F': d->character->player.sex = SEX_FEMALE; break; default: write_to_output(d, "That is not a sex..\r\n" "What IS your sex? "); return; }
case CON_QCLASS: load_result = parse_class(*arg); if (load_result == CLASS_UNDEFINED) { write_to_output(d, "\r\nThat's not a class.\r\nClass: "); return; } else GET_CLASS(d->character) = load_result;
if (d->olc) { free(d->olc); d->olc = NULL; } if (GET_PFILEPOS(d->character) < 0) GET_PFILEPOS(d->character) = create_entry(GET_PC_NAME(d->character)); /* Now GET_NAME() will work properly. */ init_char(d->character); save_char(d->character); save_player_index(); write_to_output(d, "%s\r\n*** PRESS RETURN: ", motd); STATE(d) = CON_RMOTD; /* make sure the last log is updated correctly. */ GET_PREF(d->character)= rand_number(1, 128000); GET_HOST(d->character)= strdup(d->host);
mudlog(NRM, LVL_GOD, TRUE, "%s [%s] new player.", GET_NAME(d->character), d->host);
/* Add to the list of 'recent' players (since last reboot) */ if (AddRecentPlayer(GET_NAME(d->character), d->host, TRUE, FALSE) == FALSE) { mudlog(BRF, MAX(LVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE, "Failure to AddRecentPlayer (returned FALSE)."); } break;
case CON_RMOTD: /* read CR after printing motd */ add_llog_entry(d->character, LAST_CONNECT); STATE(d) = CON_MENU; break;
case CON_MENU: { /* get selection from main menu */
load_result = enter_player_game(d);
/* Clear their load room if it's not persistant. */ if (!PLR_FLAGGED(d->character, PLR_LOADROOM)) GET_LOADROOM(d->character) = NOWHERE; save_char(d->character);
act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
STATE(d) = CON_PLAYING; MXPSendTag( d, "<VERSION>" ); if (GET_LEVEL(d->character) == 0) { do_start(d->character); send_to_char(d->character, "%s", CONFIG_START_MESSG); } look_at_room(d->character, 0); if (has_mail(GET_IDNUM(d->character))) send_to_char(d->character, "You have mail waiting.\r\n"); if (load_result == 2) { /* rented items lost */ send_to_char(d->character, "\r\n\007You could not afford your rent!\r\n" "Your possesions have been donated to the Salvation Army!\r\n"); } d->has_prompt = 0; /* We've updated to 3.1 - some bits might be set wrongly: */ REMOVE_BIT_AR(PRF_FLAGS(d->character), PRF_BUILDWALK); break; } return;
case CON_CHPWD_GETOLD: if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) { echo_on(d); write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU); STATE(d) = CON_MENU; } else { write_to_output(d, "\r\nEnter a new password: "); STATE(d) = CON_CHPWD_GETNEW; } return;
case CON_DELCNF1: echo_on(d); if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) { write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU); STATE(d) = CON_MENU; } else { write_to_output(d, "\r\nYOU ARE ABOUT TO DELETE THIS CHARACTER PERMANENTLY.\r\n" "ARE YOU ABSOLUTELY SURE?\r\n\r\n" "Please type \"yes\" to confirm: "); STATE(d) = CON_DELCNF2; } break;
case CON_DELCNF2: if (!strcmp(arg, "yes") || !strcmp(arg, "YES")) { if (PLR_FLAGGED(d->character, PLR_FROZEN)) { write_to_output(d, "You try to kill yourself, but the ice stops you.\r\n" "Character not deleted.\r\n\r\n"); STATE(d) = CON_CLOSE; return; } if (GET_LEVEL(d->character) < LVL_GRGOD) SET_BIT_AR(PLR_FLAGS(d->character), PLR_DELETED); save_char(d->character); Crash_delete_file(GET_NAME(d->character)); /* If the selfdelete_fastwipe flag is set (in config.c), remove all the * player's immediately. */ if (selfdelete_fastwipe) if ((player_i = get_ptable_by_name(GET_NAME(d->character))) >= 0) { SET_BIT(player_table[player_i].flags, PINDEX_SELFDELETE); remove_player(player_i); }
/* It is possible, if enough pulses are missed, to kick someone off while they * are at the password prompt. We'll let the game_loop()axe them. */ case CON_CLOSE: break;
default: log("SYSERR: Nanny: illegal state of con'ness (%d) for '%s'; closing connection.", STATE(d), d->character ? GET_NAME(d->character) : "<unknown>"); STATE(d) = CON_DISCONNECT; /* Safest to do. */ break; } }
So I was able to cut out the menu for when people log in. But I have to hit the enter key twice. I tried new lines and returns in the output but that doesn't work. I was wondering if anyone had any ideas.
25 Dec, 2015, thecircuitbox wrote in the 2nd comment:
Wow, that's really short. There's at least five thousand lines of code in our equivalent of nanny, and that's not counting various helpers and infrastructure. Yours looks a lot easier to work on.
I was referring to the overall line count, not the function size. Ours is busted up into a ton of little functions making a great big function pointer state machine.
So I was able to cut out the menu for when people log in. But I have to hit the enter key twice. I tried new lines and returns in the output but that doesn't work. I was wondering if anyone had any ideas.