/***************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, 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-1996 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@efn.org) *
* Gabrielle Taylor *
* 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 contains all of the OS-dependent stuff:
* startup, signals, BSD sockets for tcp/ip, i/o, timing.
*
* The data flow for input is:
* Game_loop ---> Read_from_descriptor ---> Read
* Game_loop ---> Read_from_buffer
*
* The data flow for output is:
* Game_loop ---> Process_Output ---> Write_to_descriptor -> Write
*
* The OS-dependent functions are Read_from_descriptor and Write_to_descriptor.
* -- Furey 26 Jan 1993
*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <stdarg.h>
#include <unistd.h>
#include <malloc.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
#include <crypt.h>
#include "merc.h"
#include "utils.h"
#include "telnet.h"
#include "recycle.h"
#include "tables.h"
#include "utils.h"
DECLARE_DO_FUN(do_help);
DECLARE_DO_FUN(do_look);
DECLARE_DO_FUN(do_skills);
DECLARE_DO_FUN(do_spells);
DECLARE_DO_FUN(do_outfit);
DECLARE_DO_FUN(do_unread);
DECLARE_DO_FUN(do_asave);
DECLARE_DO_FUN(do_echo);
DECLARE_DO_FUN(do_replay);
DECLARE_DO_FUN(do_quit);
/*
* Socket and TCP/IP stuff.
*/
const char echo_off_str[] = { IAC, WILL, TELOPT_ECHO, '\0' };
const char echo_on_str[] = { IAC, WONT, TELOPT_ECHO, '\0' };
const char go_ahead_str[] = { IAC, GA, '\0' };
bool rolled;
int stat1[5], stat2[5], stat3[5], stat4[5], stat5[5];
// send a class menu during chargen in a box
void class_menu( CHAR_DATA *ch ) {
char buf[MIL];
int count;
char *sep = " {g+----------------------------------------------------------------------------+{x\r\n";
char *blank = "{g | |{x\r\n";
send_to_char( "\r\n", ch );
send_to_char( sep, ch );
send_to_char( blank, ch );
send_to_char( "{g | {WCurrent Classes Exp Per Level at 40 CP {g|{x\r\n", ch );
send_to_char( blank, ch );
send_to_char( " {g| {y", ch );
for( count = 0; count < MAX_CLASS; count++) {
if ( !class_table[count].valid )
continue;
ch->class = count;
sprintf( buf, "%-30s %d",
class_table[count].name,
exp_per_level( ch, 40 ) );
buf[0] = UPPER(buf[0]);
send_to_char( buf, ch );
send_to_char( " {g| \r\n{g | {y", ch );
}
send_to_char( " {g| \r\n", ch );
send_to_char( sep, ch );
return;
}
void do_cm ( CHAR_DATA *ch, char *argument ) {
class_menu( ch );
return;
}
void race_menu( CHAR_DATA *ch ) {
char buf[MIL];
RACE_DATA *race;
int i = 0;
char *sep = " {g+----------------------------------------------------------------------------+{x\r\n";
char *blank = "{g | |{x\r\n";
send_to_char( "\r\n", ch );
send_to_char( sep, ch );
send_to_char( blank, ch );
send_to_char( "{g |{W Race Points Max Stats Race Points Max Stats {g| ", ch);
send_to_char( "{g |{W St In Wi Co De St In Wi Co De {g| ", ch);
send_to_char( "{g | ", ch );
for (race = race_first; race != NULL; race = race->next) {
if ( !race->pc_race )
continue;
sprintf( buf, "%15s{x %-3d %-2d %-2d %-2d %-2d %-2d ",
race->gen_name,
race->points,
race->stats[STAT_STR],
race->stats[STAT_INT],
race->stats[STAT_WIS],
race->stats[STAT_CON],
race->stats[STAT_DEX] );
buf[0] = UPPER(buf[0]);
send_to_char( buf, ch );
i++;
if (i % 2 == 0)
send_to_char("{g|\r\n | ", ch);
}
if (i % 2 != 0)
send_to_char(" {g|\r\n", ch);
send_to_char( blank, ch );
send_to_char( sep, ch );
return;
}
void do_rm( CHAR_DATA *ch, char * argument ) {
race_menu( ch );
return;
}
/*
* Parse a name for acceptability.
*/
bool check_parse_name(char *name)
{
/*
* Reserved words.
*/
if (is_name (name,
"all auto immortal self someone something the you demise balance circle loner honor"))
return FALSE;
/*
* Length restrictions.
*/
if (strlen(name) < 2)
return FALSE;
if (strlen(name) > 12)
return FALSE;
/*
* Alphanumerics only.
* Lock out IllIll twits.
*/
{
char *pc;
bool fIll, adjcaps = FALSE, cleancaps = FALSE;
int total_caps = 0;
fIll = TRUE;
for (pc = name; *pc != '\0'; pc++) {
if (!isalpha(*pc))
return FALSE;
if (isupper(*pc)) { /* ugly anti-caps hack */
if (adjcaps)
cleancaps = TRUE;
total_caps++;
adjcaps = TRUE;
} else
adjcaps = FALSE;
if (LOWER(*pc) != 'i' && LOWER(*pc) != 'l')
fIll = FALSE;
}
if (fIll)
return FALSE;
if (cleancaps
|| (total_caps > (strlen(name)) / 2
&& strlen(name) < 3)) return FALSE;
}
/*
* Prevent players from naming themselves after mobs.
*/
{
extern MOB_INDEX_DATA *mob_index_hash[MAX_KEY_HASH];
MOB_INDEX_DATA *pMobIndex;
int iHash;
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++) {
for (pMobIndex = mob_index_hash[iHash];
pMobIndex != NULL; pMobIndex = pMobIndex->next) {
if (is_name(name, pMobIndex->player_name))
return FALSE;
}
}
}
return TRUE;
}
/*
* Deal with sockets that haven't logged in yet.
*/
void nanny(DESCRIPTOR_DATA * d, char *argument)
{
DESCRIPTOR_DATA *d_old, *d_next;
RACE_DATA *race;
extern const char *ansi_greeting;
extern const char *no_ansi_greeting;
char buf[MAX_STRING_LENGTH];
char arg[MAX_INPUT_LENGTH];
CHAR_DATA *ch;
char *pwdnew;
char *p;
int iClass, i, x, weapon, iStat;
bool fOld;
bool BadStat = FALSE;
/* Delete leading spaces UNLESS character is writing a note */
while (isspace(*argument))
argument++;
ch = d->character;
switch (d->connected) {
default:
bug("Nanny: bad d->connected %d.", d->connected);
close_socket(d);
return;
case CON_ASK_IF_COLOUR:
if ((argument[0] == 'n') || (argument[0] == 'N'))
d->ansi = FALSE;
else
d->ansi = TRUE;
/*
* Send the greeting.
*/
{
if (d->ansi) {
write_color_to_buffer(ansi_greeting, d);
} else {
write_to_buffer(d, no_ansi_greeting, 0);
}
}
d->connected = CON_GET_NAME;
return;
case CON_GET_NAME:
if (argument[0] == '\0') {
close_socket(d);
return;
}
argument[0] = UPPER(argument[0]);
if (!check_parse_name(argument)) {
write_to_buffer(d, "Illegal name, try another.\n\rName: ", 0);
return;
}
fOld = load_char_obj(d, argument);
ch = d->character;
if (IS_SET(ch->act, PLR_DENY)) {
sprintf(log_buf, "Denying access to %s@%s.", argument,
d->host);
log_string(log_buf);
write_to_buffer(d, "You are denied access.\n\r", 0);
close_socket(d);
return;
}
if (check_reconnect(d, argument, FALSE)) {
fOld = TRUE;
} else {
if (wizlock && !IS_HERO(ch)) {
write_to_buffer(d, "The game is wizlocked.\n\r", 0);
close_socket(d);
return;
}
}
if (fOld) {
if (d->ansi)
write_to_buffer(d, C_GREEN, 0);
write_to_buffer(d, "Password: ", 0);
write_to_buffer(d, CLEAR, 0);
write_to_buffer(d, echo_off_str, 0);
d->connected = CON_GET_OLD_PASSWORD;
return;
} else {
/* New player */
if (newlock) {
write_to_buffer(d, "The game is newlocked.\n\r", 0);
close_socket(d);
return;
}
sprintf(buf,
"Please make sure that your name is appropriate for a fantasy realm.\nDid I get that right, %s (Y/N)? ",
argument);
write_to_buffer(d, buf, 0);
d->connected = CON_CONFIRM_NEW_NAME;
return;
}
if (check_playing(d, ch->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)) {
write_to_buffer(d, "Wrong password.\n\r", 0);
close_socket(d);
return;
}
if (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, echo_on_str, 0);
if (check_reconnect(d, ch->name, TRUE))
return;
if (check_playing(d, ch->name))
return;
sprintf(log_buf, "%s@%s has connected.", ch->name, d->host);
log_string(log_buf);
wiznet(log_buf, NULL, NULL, WIZ_SITES, 0, get_trust(ch));
if (IS_HERO(ch)) {
do_help(ch, "imotd");
d->connected = CON_READ_IMOTD;
} else {
do_help(ch, "motd");
d->connected = CON_READ_MOTD;
}
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->character->name))
continue;
close_socket(d_old);
}
if (check_reconnect(d, ch->name, TRUE))
return;
write_to_buffer(d, "Reconnect attempt failed.\n\rName: ", 0);
if (d->character != NULL) {
free_char(d->character);
d->character = NULL;
}
d->connected = CON_GET_NAME;
break;
case 'n':
case 'N':
write_to_buffer(d, "Name: ", 0);
if (d->character != NULL) {
free_char(d->character);
d->character = NULL;
}
d->connected = CON_GET_NAME;
break;
default:
write_to_buffer(d, "Please type Y or N? ", 0);
break;
}
close_socket(ch->desc);
break;
case CON_CONFIRM_NEW_NAME:
switch (*argument) {
case 'y':
case 'Y':
sprintf(buf, "New character.\n\rGive me a password for %s: %s",
ch->name, echo_off_str);
write_to_buffer(d, buf, 0);
d->connected = CON_GET_NEW_PASSWORD;
if (d->ansi)
SET_BIT(ch->act, PLR_COLOUR);
break;
case 'n':
case 'N':
write_to_buffer(d, "Ok, what IS it, then? ", 0);
free_char(d->character);
d->character = NULL;
d->connected = CON_GET_NAME;
break;
default:
write_to_buffer(d, "Please type Yes or No? ", 0);
break;
}
break;
case CON_GET_NEW_PASSWORD:
#if defined(unix)
write_to_buffer(d, "\n\r", 2);
#endif
if (strlen(argument) < 5) {
write_to_buffer(d,
"Password must be at least five characters long.\n\rPassword: ",
0);
return;
}
pwdnew = crypt(argument, ch->name);
for (p = pwdnew; *p != '\0'; p++) {
if (*p == '~') {
write_to_buffer(d,
"New password not acceptable, try again.\n\rPassword: ",
0);
return;
}
}
free_string(ch->pcdata->pwd);
ch->pcdata->pwd = str_dup(pwdnew);
write_to_buffer(d, "Please retype password: ", 0);
d->connected = CON_CONFIRM_NEW_PASSWORD;
break;
case CON_CONFIRM_NEW_PASSWORD:
#if defined(unix)
write_to_buffer(d, "\n\r", 2);
#endif
if (strcmp(crypt(argument, ch->pcdata->pwd), ch->pcdata->pwd)) {
write_to_buffer(d,
"Passwords don't match.\n\rRetype password: ",
0);
d->connected = CON_GET_NEW_PASSWORD;
return;
}
write_to_buffer(d, echo_on_str, 0);
write_to_buffer(d, "The following races are available:\n\r ", 0);
race_menu( ch );
write_to_buffer(d, "\r\n ", 1);
write_to_buffer(d, "\n\r", 0);
write_to_buffer(d,
"What is your race (help for more information)? ",
0);
d->connected = CON_GET_NEW_RACE;
break;
case CON_GET_NEW_RACE:
one_argument(argument, arg);
if (!strcmp(arg, "help")) {
argument = one_argument(argument, arg);
if (argument[0] == '\0')
do_help(ch, "race help");
else
do_help(ch, argument);
race_menu( ch );
write_to_buffer(d, "\r\n ", 1);
write_to_buffer(d, "\n\r", 0);
write_to_buffer(d,
"What is your race (help for more information)? ",
0);
break;
}
race = gen_race_lookup(argument);
if ((!race) || !race->pc_race ) {
write_to_buffer(d, "That's not a valid race!\n\r", 0);
write_to_buffer(d, "The following races are available:\n\r ",
0);
race_menu( ch );
write_to_buffer(d,
"What is your race? (help for more information) ",
0);
break;
}
ch->race = race;
/* initialize stats */
for (i = 0; i < MAX_STATS; i++)
ch->perm_stat[i] = race->stats[i];
ch->affected_by = ch->affected_by | race->aff;
ch->imm_flags = ch->imm_flags | race->imm;
ch->res_flags = ch->res_flags | race->res;
ch->vuln_flags = ch->vuln_flags | race->vuln;
ch->form = race->form;
ch->parts = race->parts;
/* add racial skills */
for (i = 0; i < 5; i++) {
if (race->skills[i] == NULL)
break;
group_add(ch, race->skills[i], FALSE);
}
/* add cost */
ch->pcdata->points = race->points;
ch->size = race->size;
write_to_buffer(d, "The Following classes are available:\r\n", 0);
class_menu( ch );
write_to_buffer(d, "\r\nSelect a class: ", 0);
d->connected = CON_GET_NEW_CLASS;
break;
case CON_GET_NEW_CLASS:
if (!strcmp(arg, "help")) {
argument = one_argument(argument, arg);
if (argument[0] == '\0')
do_help(ch, "class help");
else
do_help(ch, argument);
}
iClass = class_lookup(argument);
if ((iClass == -1) || !class_table[iClass].valid ) {
write_to_buffer(d, "That's not a class!\r\n", 0);
class_menu( ch );
write_to_buffer(d, "\r\nSelect a class: ", 0);
return;
}
ch->class = iClass;
sprintf(log_buf, "%s@%s new player.", ch->name, d->host);
log_string(log_buf);
wiznet("Newbie alert! $N sighted.", ch, NULL, WIZ_NEWBIE, 0, 0);
wiznet(log_buf, NULL, NULL, WIZ_SITES, 0, get_trust(ch));
write_to_buffer(d, "\n\r", 2);
write_to_buffer(d, "What is your sex (M/F)? ", 0);
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:
write_to_buffer(d, "That's not a sex.\n\rWhat IS your sex? ",
0);
return;
}
write_to_buffer(d, "\r\nPress enter to start rolling your stats.",
0);
d->connected = CON_GET_STATS;
break;
case CON_GET_STATS:
if (rolled == TRUE && (argument[0] > 4) && (argument[1] < 1))
switch (argument[0]) {
case '0':
case '1':
case '2':
case '3':
case '4':
ch->perm_stat[0] = stat1[atoi(argument)];
ch->perm_stat[1] = stat2[atoi(argument)];
ch->perm_stat[2] = stat3[atoi(argument)];
ch->perm_stat[3] = stat4[atoi(argument)];
ch->perm_stat[4] = stat5[atoi(argument)];
write_to_buffer(d,
"\r\nYou may be good, neutral, or evil.\n\r",
0);
write_to_buffer(d, "Which alignment (G/N/E)? ", 0);
d->connected = CON_GET_ALIGNMENT;
break;
default:
write_to_buffer(d, "\n\r", 0);
write_to_buffer(d,
" 0 1 2 3 4\n\r",
0);
write_to_buffer(d, " Strength :", 0);
for (x = 0; x < 5; x++) {
stat1[x] = number_range(9, 16);
sprintf(buf, " %2d", stat1[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Intelligence :", 0);
for (x = 0; x < 5; x++) {
stat2[x] = number_range(9, 16);
sprintf(buf, " %2d", stat2[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Wisdom :", 0);
for (x = 0; x < 5; x++) {
stat3[x] = number_range(9, 16);
sprintf(buf, " %2d", stat3[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Dexterity :", 0);
for (x = 0; x < 5; x++) {
stat4[x] = number_range(9, 16);
sprintf(buf, " %2d", stat4[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Constitution :", 0);
for (x = 0; x < 5; x++) {
stat5[x] = number_range(9, 16);
sprintf(buf, " %2d", stat5[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d,
"\n\r\n\r Press enter to roll again, else enter number of column: ",
0);
rolled = TRUE;
break;
} else {
write_to_buffer(d, "\r\n", 0);
write_to_buffer(d,
" 0 1 2 3 4\n\r",
0);
write_to_buffer(d, " Strength :", 0);
for (x = 0; x < 5; x++) {
stat1[x] = number_range(9, 16);
sprintf(buf, " %2d", stat1[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Intelligence :", 0);
for (x = 0; x < 5; x++) {
stat2[x] = number_range(9, 16);
sprintf(buf, " %2d", stat2[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Wisdom :", 0);
for (x = 0; x < 5; x++) {
stat3[x] = number_range(9, 16);
sprintf(buf, " %2d", stat3[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Dexterity :", 0);
for (x = 0; x < 5; x++) {
stat4[x] = number_range(9, 16);
sprintf(buf, " %2d", stat4[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d, "\n\r Constitution :", 0);
for (x = 0; x < 5; x++) {
stat5[x] = number_range(9, 16);
sprintf(buf, " %2d", stat5[x]);
write_to_buffer(d, buf, 0);
}
write_to_buffer(d,
"\n\r\n\r Press enter to roll again, else enter number of column: ",
0);
rolled = TRUE;
}
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:
write_to_buffer(d, "That's not a valid alignment.\n\r", 0);
write_to_buffer(d, "Which alignment (G/N/E)? ", 0);
return;
}
write_to_buffer(d, "\n\r", 0);
group_add(ch, "rom basics", FALSE);
group_add(ch, class_table[ch->class].base_group, FALSE);
ch->pcdata->learned[gsn_recall] = 50;
write_to_buffer(d, "Do you wish to customize this character?\n\r",
0);
write_to_buffer(d,
"Customization takes time, but allows a wider range of skills and abilities.\n\r",
0);
write_to_buffer(d, "Customize (Y/N)? ", 0);
d->connected = CON_DEFAULT_CHOICE;
break;
case CON_DEFAULT_CHOICE:
write_to_buffer(d, "\n\r", 2);
switch (argument[0]) {
case 'y':
case 'Y':
ch->gen_data = alloc_perm(sizeof(*ch->gen_data));
ch->gen_data->points_chosen = ch->pcdata->points;
do_help(ch, "group header");
list_group_costs(ch);
write_to_buffer(d,
"You already have the following skills:\n\r",
0);
do_skills(ch, "");
do_help(ch, "menu choice");
d->connected = CON_GEN_GROUPS;
break;
case 'n':
case 'N':
group_add(ch, class_table[ch->class].default_group, TRUE);
write_to_buffer(d, "\n\r", 2);
write_to_buffer(d,
"Please pick a weapon from the following choices:\n\r\r\n",
0);
buf[0] = '\0';
for (i = 0; weapon_table[i].name != NULL; i++)
if (ch->pcdata->learned[*weapon_table[i].gsn] > 0) {
strcat(buf, weapon_table[i].name);
strcat(buf, " ");
}
strcat(buf, "\n\r\n\rYour choice? ");
write_to_buffer(d, buf, 0);
d->connected = CON_PICK_WEAPON;
break;
default:
write_to_buffer(d, "Please answer (Y/N)? ", 0);
return;
}
break;
case CON_PICK_WEAPON:
write_to_buffer(d, "\n\r", 2);
weapon = weapon_lookup(argument);
if (weapon == -1
|| ch->pcdata->learned[*weapon_table[weapon].gsn] <= 0) {
write_to_buffer(d,
"That's not a valid selection. Choices are:\n\r",
0);
buf[0] = '\0';
for (i = 0; weapon_table[i].name != NULL; i++)
if (ch->pcdata->learned[*weapon_table[i].gsn] > 0) {
strcat(buf, weapon_table[i].name);
strcat(buf, " ");
}
strcat(buf, "\n\rYour choice? ");
write_to_buffer(d, buf, 0);
return;
}
ch->pcdata->learned[*weapon_table[weapon].gsn] = 40;
if (IS_IMMORTAL(ch)) {
do_help(ch, "imotd");
d->connected = CON_READ_IMOTD;
} else {
do_help(ch, "motd");
d->connected = CON_READ_MOTD;
}
break;
case CON_GEN_GROUPS:
send_to_char("\n\r", ch);
if (!str_cmp(argument, "done")) {
sprintf(buf, "Creation points: %d\n\r", ch->pcdata->points);
send_to_char(buf, ch);
if (ch->pcdata->points < 40)
ch->train = (40 - ch->pcdata->points + 1) / 2;
send_to_char(buf, ch);
send_to_char
("\r\nPlease pick a weapon from the following choices:\n\r",
ch);
buf[0] = '\0';
for (i = 0; weapon_table[i].name != NULL; i++)
if (ch->pcdata->learned[*weapon_table[i].gsn] > 0) {
strcat(buf, weapon_table[i].name);
strcat(buf, "\r\n ");
}
strcat(buf, "\n\rYour choice? ");
write_to_buffer(d, buf, 0);
d->connected = CON_PICK_WEAPON;
break;
}
if (!parse_gen_groups(ch, argument))
send_to_char
("Choices are: list, learned, premise, add, drop, info, help, and done.\n\r",
ch);
send_to_char( "Choice (add,drop,list,help)? ", ch );
break;
case CON_READ_IMOTD:
write_to_buffer(d, "\n\r", 2);
do_help(ch, "motd");
d->connected = CON_READ_MOTD;
break;
case CON_READ_MOTD:
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);
}
send_to_char
("Welcome to Alanthia! Please do not feed the mobiles.\n\r",
ch);
ch->next = char_list;
char_list = ch;
d->connected = CON_PLAYING;
reset_char(ch);
if (ch->max_blood < ch->level) {
ch->max_blood = ch->level;
ch->pcdata->perm_blood = ch->level;
}
if (ch->level == 0) {
char color_title[] = { 'G', 'M', 'B', 'C', 'Y', 'R' };
char color = color_title[number_range(0, 5)];
ch->perm_stat[class_table[ch->class].attr_prime] += 1;
ch->level = 1;
ch->exp = exp_per_level(ch, ch->pcdata->points);
ch->hit = ch->max_hit;
ch->mana = ch->max_mana;
ch->move = ch->max_move;
ch->blood = ch->max_blood;
ch->train = 3;
ch->practice = 5;
ch->outfit = FALSE;
if (IS_VAMPIRE(ch) || IS_WRAITH(ch)) {
ch->pcdata->condition[COND_THIRST] = -1;
ch->pcdata->condition[COND_HUNGER] = -1;
ch->pcdata->condition[COND_DRUNK] = -1;
}
SET_BIT(ch->comm, COMM_SHOW_AFFECTS);
SET_BIT(ch->comm, COMM_ANNOUNCE);
SET_BIT(ch->act, PLR_AUTOEXIT);
SET_BIT(ch->act, PLR_AUTODAMAGE);
SET_BIT(ch->act, PLR_AUTOLOOT);
SET_BIT(ch->act, PLR_AUTOSAC);
SET_BIT(ch->act, PLR_AUTOASSIST);
SET_BIT(ch->act, PLR_AUTOSPLIT);
ch->prompt = str_dup("{c<%hhp %mm %vmv %bbp>{x ");
sprintf(buf, "the {%cN{%ceWBiE{x", color, LOWER(color));
set_title(ch, buf);
write_to_buffer(d, "\n\r", 2);
char_to_room(ch, get_room_index(ROOM_VNUM_SCHOOL));
do_outfit(ch, "");
send_to_char("\n\r", ch);
do_help(ch, "NEWBIE INFO");
send_to_char("\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));
}
/*
* Sanity checking for bogus levels, bad stats, etc. WDL, 4.10.98
*/
/* Check for bad stats */
for (iStat = 0; iStat < 5; iStat++) {
if ((ch->perm_stat[iStat] >= 26)
|| (ch->perm_stat[iStat] <= 0)) {
ch->perm_stat[iStat] = 12;
BadStat = TRUE;
}
}
/* Holler loudly */
if (BadStat == TRUE) {
wiznet("$N had bogus stat, fixing...", ch, NULL,
WIZ_SITES, 0, 0);
sprintf(log_buf, "**BUG** %s@%s had bogus stats.", ch->name,
d->host);
log_string(log_buf);
}
/* Check for bad levels */
if ((ch->level < 0) || (ch->level > MAX_LEVEL)) {
ch->level = 1;
wiznet("$N has bogus level! Possible hack attempt!", ch, NULL,
WIZ_SITES, 0, 0);
sprintf(log_buf, "**BUG** %s@%s used bogus level! Kill them.",
ch->name, d->host);
log_string(log_buf);
}
act("$n appears in the room.", ch, NULL, NULL, TO_ROOM);
/* For the Announce Channel */
announce("{c[{RANNOUNCE{c] $n has stumbled into Alanthia.{x", ch);
do_look(ch, "auto");
save_char_obj(ch);
wiznet("$N has left real life behind.", ch, NULL, WIZ_LOGINS,
WIZ_SITES, get_trust(ch));
if (ch->pet != NULL) {
char_to_room(ch->pet, ch->in_room);
act("$n appears in the room.", ch->pet, NULL, NULL, TO_ROOM);
}
do_unread(ch, "");
break;
}
return;
}