/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik Strfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Thanks to abaddon for proof-reading our comm.c and pointing out bugs. *
* Any remaining bugs are, of course, our work, not his. :) *
* *
* Much time and thought has gone into this software and you are *
* benefitting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************/
/***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
****************************************************************************/
/****************************************************************************
* This file is just the stock nanny() function ripped from comm.c. It *
* seems to be a popular task for new mud coders, so what the heck? *
***************************************************************************/
#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#include <sys/time.h>
#endif
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h> /* OLC -- for close read write etc */
#include <stdarg.h> /* printf_to_char */
#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "tables.h"
#if defined(macintosh) || defined(MSDOS)
extern const char echo_off_str[];
extern const char echo_on_str[];
extern const char go_ahead_str[];
#endif
#if defined(unix)
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "telnet.h"
extern const char echo_off_str[];
extern const char echo_on_str[];
extern const char go_ahead_str[];
#endif
/*
* OS-dependent local functions.
*/
#if defined(macintosh) || defined(MSDOS)
void game_loop_mac_msdos args ((void));
bool read_from_descriptor args ((DESCRIPTOR_DATA * d));
bool write_to_descriptor args ((int desc, char *txt, int length));
#endif
#if defined(unix)
void game_loop_unix args ((int control));
int init_socket args ((int port));
void init_descriptor args ((int control));
bool read_from_descriptor args ((DESCRIPTOR_DATA * d));
bool write_to_descriptor args ((int desc, char *txt, int length));
#endif
/*
* * Other local functions (OS-independent).
* */
bool check_parse_name args ((char *name));
bool check_reconnect args ((DESCRIPTOR_DATA * d, char *name, bool fConn));
bool check_playing args ((DESCRIPTOR_DATA * d, char *name));
void enter_game args ((DESCRIPTOR_DATA * d));
/*
* Global variables.
*/
extern DESCRIPTOR_DATA *descriptor_list; /* All open descriptors */
extern DESCRIPTOR_DATA *d_next; /* Next descriptor in loop */
extern FILE *fpReserve; /* Reserved file handle */
extern bool god; /* All new chars are gods! */
extern bool merc_down; /* Shutdown */
extern bool wizlock; /* Game is wizlocked */
extern bool newlock; /* Game is newlocked */
extern char str_boot_time[MAX_INPUT_LENGTH];
extern time_t current_time; /* time of this pulse */
extern int mud_telnetga, mud_ansicolor;
/*
* Deal with sockets that haven't logged in yet.
*/
void nanny (DESCRIPTOR_DATA * d, char *argument)
{
DESCRIPTOR_DATA *d_old, *d_next;
char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *ch;
char *pwdnew;
char *p;
int race, i, sn;
bool fOld;
/* Delete leading spaces UNLESS character is writing a note */
if (d->connected != CON_NOTE_TEXT)
{
while ( isspace(*argument) )
argument++;
}
ch = d->character;
switch (d->connected)
{
default:
logstr (LOG_BUG, "Nanny: bad d->connected %d.", d->connected);
close_socket (d);
return;
case CON_ANSI:
if (argument[0] == '\0' || UPPER (argument[0]) == 'Y')
{
d->ansi = TRUE;
send_to_desc ("{RAnsi enabled!{x\n\r", d);
d->connected = CON_GET_NAME;
{
extern char *help_greeting;
if (help_greeting[0] == '.')
send_to_desc (help_greeting + 1, d);
else
send_to_desc (help_greeting, d);
}
break;
}
if (UPPER (argument[0]) == 'N')
{
d->ansi = FALSE;
send_to_desc ("Ansi disabled!\n\r", d);
d->connected = CON_GET_NAME;
{
extern char *help_greeting;
if (help_greeting[0] == '.')
send_to_desc (help_greeting + 1, d);
else
send_to_desc (help_greeting, d);
}
break;
}
else
{
send_to_desc ("Do you want ANSI? Is this in {Cc{Go{Bl{Ro{Yu{Mr{x? (Y/N) ", d);
return;
}
case CON_GET_NAME:
if (argument[0] == '\0')
{
close_socket (d);
return;
}
argument[0] = UPPER (argument[0]);
/* if (!check_parse_name (argument))
{
send_to_desc ("Illegal name, try another.\n\r{B[{xName{B]{x ", d);
return;
} */
fOld = load_char_obj (d, argument);
ch = d->character;
if (IS_SET (ch->act, PLR_DENY))
{
logstr (LOG_SECURITY, "Denying access to %s@%s.", argument, d->host);
send_to_desc ("You are denied access.\n\r", d);
close_socket (d);
return;
}
if (check_ban (d->host, BAN_PERMIT)
&& !IS_SET (ch->act, PLR_PERMIT))
{
send_to_desc ("Your site has been banned from this mud.\n\r", d);
close_socket (d);
return;
}
if (check_reconnect (d, argument, FALSE))
fOld = TRUE;
else {
if (wizlock && !IS_IMMORTAL (ch)) {
send_to_desc ("The game is wizlocked.\n\r", d);
close_socket (d);
return;
}
}
if (fOld)
{
/* Old player */
send_to_desc ("{B[{xPassword{B]{x ", d);
write_to_buffer (d, echo_off_str, 0);
d->connected = CON_GET_OLD_PASSWORD;
return;
}
else
{
/* New player */
if (newlock)
{
send_to_desc ("The game is newlocked.\n\r", d);
close_socket (d);
return;
}
if (check_ban (d->host, BAN_NEWBIES))
{
send_to_desc ("New players are not allowed from your site.\n\r", 0);
close_socket (d);
return;
}
sprintf (buf, "Make sure you have a proper name. Names from the show,\n\r"
"for instance Goku, Gohan or Vegeta, are not allowed. This\n\r"
"includes obvious variations such as Gotu, or Vegeto.\n\r"
"Immortals reserve final say; we can change your name at\n\r"
"moments notice!\n\r"
"\n\r"
"{B[{xIs %s correct? (Y/N){B]{x ", argument);
send_to_desc (buf, d);
d->connected = CON_CONFIRM_NEW_NAME;
return;
}
break;
case CON_GET_OLD_PASSWORD:
#if defined(unix)
write_to_buffer (d, "\n\r", 2);
#endif
if (strcmp (crypt (argument, ch->pcdata->pwd), ch->pcdata->pwd))
{
send_to_desc ("Wrong password!\n\r", d);
close_socket (d);
return;
}
write_to_buffer (d, echo_on_str, 0);
if (check_playing (d, ch->name))
return;
if (check_reconnect (d, ch->name, TRUE))
return;
logstr (LOG_CONNECT, "%s@%s has connected.", ch->name, d->host);
wiznet (log_buf, NULL, NULL, WIZ_SITES, 0, ch->level);
if (ch->desc->ansi)
SET_BIT (ch->act, PLR_COLOUR);
else
REMOVE_BIT (ch->act, PLR_COLOUR);
/*
if (IS_IMMORTAL (ch))
{
//do_function (ch, &do_help, "imotd");
d->connected = CON_READ_MOTD;
}
else
{
//do_function (ch, &do_help, "motd");
d->connected = CON_READ_MOTD;
}
*/
enter_game (d);
break;
/* RT code for breaking link */
case CON_BREAK_CONNECT:
switch (*argument)
{
case 'y':
case 'Y':
for (d_old = descriptor_list; d_old != NULL;
d_old = d_next)
{
d_next = d_old->next;
if (d_old == d || d_old->character == NULL)
continue;
if (str_cmp (ch->name, d_old->original ?
d_old->original->name : d_old->
character->name))
continue;
close_socket (d_old);
}
if (check_reconnect (d, ch->name, TRUE))
return;
send_to_desc ("Reconnect attempt failed.\n\r{B[{xName{B]{x ", d);
if (d->character != NULL)
{
free_char (d->character);
d->character = NULL;
}
d->connected = CON_GET_NAME;
break;
case 'n':
case 'N':
send_to_desc ("{B[{xName{B]{x ", d);
if (d->character != NULL)
{
free_char (d->character);
d->character = NULL;
}
d->connected = CON_GET_NAME;
break;
default:
send_to_desc ("(Y)es or (N)o? ", d);
break;
}
break;
case CON_CONFIRM_NEW_NAME:
switch (*argument)
{
case 'y':
case 'Y':
sprintf (buf,
"New character!\n\r\n\r{B[{xWhat is your new password?{B]{x %s",
echo_off_str);
send_to_desc (buf, d);
d->connected = CON_GET_NEW_PASSWORD;
if (ch->desc->ansi)
SET_BIT (ch->act, PLR_COLOUR);
break;
case 'n':
case 'N':
send_to_desc ("{B[{xName{B]{x ", d);
free_char (d->character);
d->character = NULL;
d->connected = CON_GET_NAME;
break;
default:
send_to_desc ("(Y)es or (N)o? ", d);
break;
}
break;
case CON_GET_NEW_PASSWORD:
if (strlen (argument) < 5)
{
send_to_desc
("\n\rPassword must be at least five characters long.\n\r{B[{xPassword{B]{x ", d);
return;
}
pwdnew = crypt (argument, ch->name);
for (p = pwdnew; *p != '\0'; p++)
{
if (*p == '~')
{
send_to_desc ("\n\rNew password not acceptable, try again.\n\r{B[{xPassword{B]{x ", d);
return;
}
}
free_string (ch->pcdata->pwd);
ch->pcdata->pwd = str_dup (pwdnew);
send_to_desc ("\n\r{B[{xRetype password{B]{x ", d);
d->connected = CON_CONFIRM_NEW_PASSWORD;
break;
case CON_CONFIRM_NEW_PASSWORD:
if (strcmp (crypt (argument, ch->pcdata->pwd), ch->pcdata->pwd))
{
send_to_desc ("\n\rPasswords don't match.\n\r{B[{xRetype password{B]{x ", d);
d->connected = CON_GET_NEW_PASSWORD;
return;
}
write_to_buffer (d, echo_on_str, 0);
send_to_desc ("\n\rPlease select a race:\n\r"
" {b[{Bhuman {b]{x The inhabitants of Earth. Decent at anything.\n\r"
" {b[{Bsaiya-jin {b]{x Born fighters, they are strong, but not very intelligent.\n\r"
" {b[{Bnamek {b]{x The green-skinned Nameks possess a strong constitution, and the\n\r"
" ability to heal quickly. They are sexless.\n\r"
" {b[{Bhalf-breed {b]{x The offspring of a human and saiya-jin is a half-breed. They\n\r"
" are not as strong as saiya-jins, being more average like humans.\n\r"
" {b[{Bicer {b]{x A terrible, evil race. Strong, but also not dexterous.\n\r"
" {b[{Bandroid {b]{x Robots, possibly built from a person. Though lacking intelligence,\n\r"
" they have high strength and constitution.\n\r"
" {b[{Bbio-android{b]{x Similar to robots, but built from the cells of many races. Still\n\r"
" lacking intelligence, they are stronger than androids.\n\r", d);
/*
for (race = 1; race_table[race].name != NULL; race++)
{
if (!race_table[race].pc_race)
break;
if (!race_table[race].can_select)
continue;
write_to_buffer (d, " ", 2);
write_to_buffer (d, race_table[race].name, 0);
write_to_buffer (d, "\n\r", 2);
}
write_to_buffer (d, "\n\r", 0);
*/
send_to_desc ("Each race is as powerful as the next -- none are dominating.\n\r\n\r", d);
send_to_desc ("Type 'help <race>' for more information about that race.\n\r", d);
send_to_desc ("{B[{xRace{B]{x ", d);
d->connected = CON_GET_NEW_RACE;
logstr (LOG_GAME, "%s@%s new player.", ch->name, d->host);
wiznet ("Newbie alert! $N sighted.", ch, NULL, WIZ_NEWBIE, 0, 0);
wiznet (log_buf, NULL, NULL, WIZ_SITES, 0, ch->level);
break;
case CON_GET_NEW_RACE:
one_argument (argument, arg);
if (!strcmp (arg, "help")) {
argument = one_argument (argument, arg);
if (argument[0] == '\0')
send_to_desc ("Type 'help <race>' for more information about that race.\n\r", d);
else
do_function (ch, &do_help, argument);
send_to_desc ("{B[{xRace{B]{x ", d);
break;
}
race = race_lookup (argument);
if (race == 0 || !race_table[race].pc_race || !race_table[race].can_select)
{
send_to_desc ("Not a valid race!\n\r", d);
send_to_desc ("Please select a race:\n\r"
" {b[{Bhuman {b]{x The inhabitants of Earth. Decent at anything.\n\r"
" {b[{Bsaiya-jin {b]{x Born fighters, they are strong, but not very intelligent.\n\r"
" {b[{Bnamek {b]{x The green-skinned Nameks possess a strong constitution, and the\n\r"
" ability to heal quickly. They are sexless.\n\r"
" {b[{Bhalf-breed {b]{x The offspring of a human and saiya-jin is a half-breed. They\n\r"
" are not as strong as saiya-jins, being more average like humans.\n\r"
" {b[{Bicer {b]{x A terrible, evil race. Strong, but also not dexterous.\n\r"
" {b[{Bandroid {b]{x Robots, possibly built from a person. Though lacking intelligence,\n\r"
" they have high strength and constitution.\n\r"
" {b[{Bbio-android{b]{x Similar to robots, but built from the cells of many races. Still\n\r"
" lacking intelligence, they are stronger than androids.\n\r", d);
send_to_desc ("Each race is as powerful as the next -- none are dominating.\n\r", d);
send_to_desc ("Type 'help <race>' for more information about that race.\n\r", d);
send_to_desc ("{B[{xRace{B]{x ", d);
break;
}
ch->race = race;
/* initialize stats */
for (i = 0; i < MAX_STATS; i++)
ch->perm_stat[i] = pc_race_table[race].stats[i];
ch->affected_by = ch->affected_by | race_table[race].aff;
ch->imm_flags = ch->imm_flags | race_table[race].imm;
ch->res_flags = ch->res_flags | race_table[race].res;
ch->vuln_flags = ch->vuln_flags | race_table[race].vuln;
ch->form = race_table[race].form;
ch->parts = race_table[race].parts;
/* add skills */
for (i = 0; i < 5; i++)
{
if ((sn = skill_lookup(pc_race_table[ch->race].skills[i])) == -1)
break;
if (ch->pcdata->learned[sn] == 0)
ch->pcdata->learned[sn] = 1;
}
// etc
ch->size = pc_race_table[race].size;
ch->pcdata->learned[gsn_hand_to_hand] = 1;
ch->pcdata->learned[gsn_dodge] = 1;
ch->pcdata->learned[gsn_kick] = 1;
// Skip if the race is always neutral
if (race == race_lookup("namek")) {
ch->sex = SEX_NEUTRAL;
ch->pcdata->true_sex = SEX_NEUTRAL;
send_to_desc ("Select an alignment:\n\r"
" {b[{B(g)ood {b]\n\r"
" [{B(n)eutral{b]\n\r"
" [{B(e)vil {b]{x\n\r"
"This is your general outlook on life; your moral values. Alignment is \n\r"
" not permanent and changes dynamically.\n\r", d);
send_to_desc ("{B[{xAlignment{B]{x ", d);
d->connected = CON_GET_ALIGNMENT;
}
else {
send_to_desc ("Select your sex:\n\r"
" {b[{B(m)ale {b]\n\r"
" [{B(f)emale{b]{x\n\r"
"Sex is a personal choice. Neither gender has any advantages.\n\r", d);
send_to_desc ("{B[{xGender{B]{x ", d);
d->connected = CON_GET_NEW_SEX;
}
break;
case CON_GET_NEW_SEX:
switch (argument[0])
{
case 'm':
case 'M':
ch->sex = SEX_MALE;
ch->pcdata->true_sex = SEX_MALE;
break;
case 'f':
case 'F':
ch->sex = SEX_FEMALE;
ch->pcdata->true_sex = SEX_FEMALE;
break;
default:
send_to_desc ("That's not a sex. Select your sex:\n\r"
" {b[{B(m)ale {b]\n\r"
" [{B(f)emale{b]{x\n\r"
"Sex is a personal choice. Neither gender has any advantages.\n\r", d);
send_to_desc ("{B[{xGender{B]{x ", d);
return;
}
send_to_desc ("Select an alignment:\n\r"
" {b[{B(g)ood {b]\n\r"
" [{B(n)eutral{b]\n\r"
" [{B(e)vil {b]{x\n\r"
"This is your general outlook on life; your moral values. Alignment is \n\r"
" not permanent and changes dynamically.\n\r", d);
send_to_desc ("{B[{xAlignment{B]{x ", d);
d->connected = CON_GET_ALIGNMENT;
break;
case CON_GET_ALIGNMENT:
switch (argument[0]) {
case 'g':
case 'G':
ch->alignment = 750;
break;
case 'n':
case 'N':
ch->alignment = 0;
break;
case 'e':
case 'E':
ch->alignment = -750;
break;
default:
send_to_desc ("That's not a valid alignment.\n\r", d);
send_to_desc ("Select an alignment:\n\r"
" {b[{B(g)ood {b]\n\r"
" [{B(n)eutral{b]\n\r"
" [{B(e)vil {b]{x\n\r"
"This is your general outlook on life; your moral values. Alignment is \n\r"
" not permanent and changes dynamically.\n\r", d);
send_to_desc ("{B[{xAlignment{B]{x ", d);
return;
}
write_to_buffer (d, "\n\r", 0);
//do_function (ch, &do_help, "motd");
//d->connected = CON_READ_MOTD;
enter_game (d);
break;
case CON_READ_IMOTD:
write_to_buffer (d, "\n\r", 2);
do_function (ch, &do_help, "motd");
d->connected = CON_READ_MOTD;
break;
/* states for new note system, (c)1995-96 erwin@pip.dknet.dk */
/* ch MUST be PC here; have nwrite check for PC status! */
case CON_NOTE_TO:
handle_con_note_to (d, argument);
break;
case CON_NOTE_SUBJECT:
handle_con_note_subject (d, argument);
break;
case CON_NOTE_EXPIRE:
handle_con_note_expire (d, argument);
break;
case CON_NOTE_TEXT:
handle_con_note_text (d, argument);
break;
case CON_NOTE_FINISH:
handle_con_note_finish (d, argument);
break;
case CON_FUSE_SLAVE:
break;
case CON_READ_MOTD:
enter_game (d);
break;
}
return;
}
void enter_game (DESCRIPTOR_DATA * d) {
char buf[MAX_STRING_LENGTH];
CHAR_DATA *ch;
ch = d->character;
if (ch->pcdata == NULL || ch->pcdata->pwd[0] == '\0') {
write_to_buffer (d, "Warning! Null password!\n\r", 0);
write_to_buffer (d, "Please report old password with bug.\n\r", 0);
write_to_buffer (d, "Type 'password null <new password>' to fix.\n\r", 0);
}
write_to_buffer (d, "\n\rWelcome ... to the Arena!\n\r", 0);
ch->next = char_list;
char_list = ch;
d->connected = CON_PLAYING;
reset_char (ch);
if (ch->level == 0)
{
if(mud_ansicolor)
SET_BIT (ch->act, PLR_COLOUR);
if(mud_telnetga)
SET_BIT (ch->comm, COMM_TELNET_GA);
ch->act = PLR_AUTOLOOT|PLR_AUTOEXIT|PLR_AUTOZENNI|PLR_AUTOSAC|PLR_AUTOSPLIT;
ch->level = 1;
ch->pl = 1000;
ch->cur_pl = 25;
ch->max_hit = ch->perm_stat[STAT_CON] * 5;
ch->max_ki = 10*(ch->perm_stat[STAT_WIS]+ch->perm_stat[STAT_INT]+ch->perm_stat[STAT_CON])/3;
ch->hit = ch->max_hit;
ch->ki = ch->max_ki;
ch->pcdata->perm_hit = ch->max_hit;
ch->pcdata->perm_ki = ch->max_ki;
ch->zenni = 250;
ch->train = 50;
sprintf (buf, "the %s", title_table[ch->level][ch->sex == SEX_FEMALE ? 1 : 0]);
set_title (ch, buf);
// New eq:
//obj_to_char (create_object (get_obj_index (OBJ_VNUM_MAP), 0), ch);
char_to_room (ch, get_room_index (ROOM_VNUM_SCHOOL));
sendch ("\n\r", ch);
do_function (ch, &do_help, "newbie info");
sendch ("\n\r", ch);
}
else if (ch->in_room != NULL)
char_to_room (ch, ch->in_room);
else if (IS_IMMORTAL (ch))
char_to_room (ch, get_room_index (ROOM_VNUM_CHAT));
else
char_to_room (ch, get_room_index (ROOM_VNUM_TEMPLE));
act ("$n has entered the Arena.", ch, NULL, NULL, TO_ROOM);
do_function (ch, &do_look, "auto");
wiznet ("$N has left real life behind.", ch, NULL, WIZ_LOGINS, WIZ_SITES, ch->level);
if (ch->pet != NULL) {
char_to_room (ch->pet, ch->in_room);
act ("$n has entered the Arena.", ch->pet, NULL, NULL, TO_ROOM);
}
sendch("\n", ch);
do_function (ch, &do_board, "");
}