w/**************************************************************************/
// nanny.cpp - Deal with sockets that haven't logged in yet
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with all the licenses *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
***************************************************************************
* >> Original Diku Mud copyright (c)1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, & Katja Nyboe. *
* >> Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* >> ROM 2.4 is copyright 1993-1995 Russ Taylor and has been brought to *
* you by the ROM consortium: Russ Taylor(rtaylor@pacinfo.com), *
* Gabrielle Taylor(gtaylor@pacinfo.com) & Brian Moore(rom@rom.efn.org) *
* >> Oblivion 1.2 is copyright 1996 Wes Wagner *
**************************************************************************/
#include "comm.h"
#include "clan.h"
#include "nanny.h"
#include "roles.h"
#include "intro.h"
#include "offmoot.h"
#include "namegen.h"
#include "security.h"
#include "channels.h"
#include "msp.h"
#include "pload.h"
void roll_stats(connection_data *d);
int count_creation_connections_per_hour(connection_data *d);
bool check_connection(connection_data *d);
void add_connection(connection_data *d);
void nanny_read_motd(connection_data *d, char *);
void nannysup_past_email_check(connection_data *d, const char *);
void nannysup_setprime_stats( char_data *ch );
void mp_login_trigger( char_data *ch);
void nsupport_newbie_alert( char_data *ch, bool created );
int name_confirmed;
DECLARE_DO_FUN( do_doublexp );
#ifdef unix
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' };
#else
const char echo_off_str [] = { '\0', '\0', '\0' };
const char echo_on_str [] = { '\0' };
const char go_ahead_str [] = { '\0' };
#endif
// locals
typedef struct creation_counter_data
{
struct creation_counter_data* next;
char *ip;
time_t time;
} CREATION_COUNTER_DATA;
static CREATION_COUNTER_DATA* creation_counter;
DECLARE_DO_FUN( do_unread );
DECLARE_DO_FUN( do_raceinfo );
DECLARE_DO_FUN( do_classinfo );
void check_offline_letgain(char_data *ch);
void check_death_update(void);
void display_legal_message(char_data *ch);
/**************************************************************************/
char * creation_titlebar(char *fmt, ...)
{
char buf [MSL];
char line[MSL];
static char returnbuf[MSL];
int spaces;
// format all the text into buf
va_list args;
va_start(args, fmt);
vsnprintf(buf, MSL, fmt, args);
va_end(args);
//=============================================================================\r\n", ch);
if(c_str_len(buf)<1 || (c_str_len(buf)==1 && (buf[0]=='-' || buf[0]=='=') ))
{
return("\r\n");
}
if(c_str_len(buf)>78)
{
sprintf(returnbuf,"%s\r\n",buf);
return returnbuf;
}
spaces= (74-c_str_len(buf))/2;
for(int j=0;j<spaces; j++)
{
line[j]='=';
}
line[spaces]='\0';
sprintf(returnbuf,"-%s`# `=c%s `&%s-\r\n",line, buf, line);
return returnbuf;
}
/**************************************************************************/
void connected_to_CON_REROLL_STATS(connection_data *d)
{
roll_stats(d);
add_connection(d);
write_to_buffer(d,"If this is your first character here we recommending\r\n",0);
write_to_buffer(d,"accepting these stats till you know what they all mean.\r\n",0);
write_to_buffer(d,"(read the newbie doc on the web page for a light explaination)\r\n",0);
d->connected_state = CON_REROLL_STATS;
}
/**************************************************************************/
// this is run when a player chooses to not customise,
// if customisation is disabled in the gamesettings
// or they have choosen a class which has customising disabled
void nanny_new_player_not_customizing(connection_data *d)
{
char_data *ch=d->character;
group_add(ch,class_table[ch->clss].default_group,true, 1);
write_to_buffer( d, "\r\n", 2 );
if(IS_IRCCON(d)){
do_help( ch, "irc-motd" );
}else{
do_help( ch, "motd" );
}
ch->hit_return_to_continue();
d->connected_state = CON_READ_MOTD;
}
/**************************************************************************/
void connected_to_CON_GET_ALLIANCE(connection_data *d)
{
write_to_buffer(d,
"`cYou must now choose your alignment, alignment is very important as it \r\n"
"`eaffects how you are expected to roleplay your character, and acting in a \r\n"
"`cmanner out-of-alignment can invite penalties from the gods/goddesses of\r\n"
"`cthe realm. Only pick an extreme alignment if you can and will live up\r\n"
"`cto it, otherwise you might do yourself great harm.\r\n\r\n",0);
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
write_to_buffer(d,
"`cThe first half of you alignment is your ALLIANCE towards good and evil,\r\n"
"`cthis value can be from -2 to 2 (including 0 being neutral) 2 being good\r\n"
"`cand -2 being evil. \r\n`cWhat value do you want for your alliance?`c ",0);
}else{
write_to_buffer(d,
"`cThe first half of you alignment is your ALLIANCE towards good and evil,\r\n"
"`cthis value can be from -3 to 3 (including 0 being neutral) 3 being extreme\r\n"
"`cgood and -3 being extreme evil. \r\n`cWhat value do you want for your alliance?`c ",0);
}
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
d->connected_state = CON_GET_ALLIANCE;
}
/**************************************************************************/
void connected_to_CON_GET_NEW_CLASS(connection_data *d)
{
int iClass;
char buf[MSL];
strcpy( buf, "[" );
for( iClass = 0; !IS_NULLSTR(class_table[iClass].name); iClass++ )
{
if(!class_table[iClass].creation_selectable
|| class_table[iClass].remort_number > d->creation_remort_number)
continue;
if(race_table[CH(d)->race]->class_exp[iClass]<1000)
continue;
if(iClass > 0 ){
strcat( buf, " " );
}
strcat( buf, class_table[iClass].name );
if(!GAMESETTING(GAMESET_CLASS_CREATION_NO_STAR)){
if(IS_SET(class_table[iClass].flags, CLASSFLAG_MAGIC_ANTIPATHY)){
strcat( buf, "`Y*`c" );
}
}
}
strcat( buf, "]");
CH(d)->println("`cSelect a class:");
CH(d)->wrapln(buf);
if(!GAMESETTING(GAMESET_CLASS_CREATION_NO_STAR)){
CH(d)->println("`cnote: only the slave class is available to new players.");
}
if(!GAMESETTING5(GAMESET5_CLASSINFO_DISABLED_IN_CREATION)){
CH(d)->wraplnf(
"Note: You can use `=Cclassinfo`c to obtain information about "
"the prime attributes of classes, and base xp values for your "
"choosen city (%s).", lowercase(race_table[CH(d)->race]->name));
}
CH(d)->println("--> " );
if(IS_IRCCON(d)){
CH(d)->println("");
}
d->connected_state = CON_GET_NEW_CLASS;
}
/**************************************************************************/
void nanny_char_version_updates(char_data *ch)
{
char tempbuf[MSL];
if(ch->version<8)
{
ch->practice+=3;
ch->train+=2;
int langsn=race_table[ch->race]->language->gsn;
if(langsn>0){
ch->pcdata->learned[langsn]=100;
}
ch->language=race_table[ch->race]->language;
}
if(ch->version==0)
{
ch->practice=9;
ch->train=5;
}
// reset players default short description
if(ch->short_descr[0]=='\0')
{
sprintf(tempbuf,"a %s %s",
(ch->sex==0 ? "sexless" : ch->sex==1 ? "male" : "female"),
race_table[ch->race]->name);
ch->short_descr= str_dup(tempbuf);
}
if(ch->version<9){
ch->printf("There is a problem with your character, version number is less than 9!\r\n"
"Talk to the admin about it.\r\n");
}
// end of stat rolling
}
/**************************************************************************/
void nanny_get_email(connection_data *c, const char *argument)
{
int result;
char logbuf[MSL];
if(IS_NULLSTR(argument)){
write_to_buffer(c,"An email address is required for all characters.\r\n",0);
write_to_buffer(c,"This information is kept private and not distributed.\r\n",0);
write_to_buffer(c,"Please type in your email address now:\r\n",0);
return;
}
CH(c)->printf("`=j%s`c", creation_titlebar("="));
logf("Checking for email ban with check_email_ban(%d, %s)",
c->connected_socket, argument);
result=check_email_ban(c, (char*)argument);
logf("check_email_ban returned = %d", result);
switch(result){
default:
bugf("handle_get_email(): unknown result of %d from check_email_ban()!",result);
do_abort(); // get a coredump and debug it
break;
case 0: // 0 accepted email, email an id code to them
{
char unlockbuf[20];
sprintf(unlockbuf,"%X", number_range(0x100000,0xFFFFFF));
// Log the email addy and details to file
sprintf(logbuf,"%-13s from '%s' accepted email '%s', unlock = %s",
CH(c)->name, c->remote_hostname, argument, unlockbuf);
append_datetimestring_to_file( EMAILADDRESSES_FILE, logbuf);
replace_string(CH(c)->pcdata->unlock_id, unlockbuf);
email_descriptor_unlock_id(c);
CH(c)->wraplnf("An email has been sent to '%s' "
"with an unlock id", CH(c)->pcdata->email);
}
nannysup_past_email_check(c,argument); // finished handling the email checks
break;
case 1: // 1 email rejected, they need another attempt.
// do nothing
sprintf(logbuf,"%-13s from '%s' rejected email '%s'",
CH(c)->name, c->remote_hostname, argument);
append_datetimestring_to_file( EMAILADDRESSES_FILE, logbuf);
break;
case 2: // 2 if they should be disconnected
connection_close(c);
break;
}
}
/**************************************************************************/
// run when waiting for the IP addy to resolve on a newbie
void nanny_resolve_ip(connection_data *c, const char *argument)
{
if(c->resolved){
write_to_buffer( c,"\r\n",0);
nannysup_email_check(c,argument);
}else{
if(c->outtop==0){
c->write(".", 1);
if(c->connected_state_pulse_counter%30==0){
c->write("\r\n",2);
}
}
if(++c->connected_state_pulse_counter>PULSE_PER_SECOND*60){
// skip the whole process.
c->resolved=true;
write_to_buffer( c,"\r\nResolving timed out.",0);
#ifdef WIN32
bugf("Resolver timed out for %s - if this happens all the "
"time disable resolving in game settings or turn "
"on local resolving. (note: the resolver hasnt' been "
"fully developed for win9x)", c->remote_hostname);
#else
bugf("Resolver timed out for %s", c->remote_hostname);
#endif
}
}
}
/**************************************************************************/
// called when someone has an id code they have to key in
void nanny_enter_unlock_id(connection_data *d, const char *argument)
{
char buf[MSL];
if(IS_NULLSTR(argument)){
CH(d)->printf("Enter the unlock code for '%s' or type `=Cquit`c:`1",
CH(d)->name);
return;
}
if(!str_cmp("quit",argument)){
CH(d)->printf("Disconnecting you now, come back when you have the code.`1");
connection_close( d );
return;
}
if(!str_cmp("resend",argument)){
email_descriptor_unlock_id(d);
CH(d)->wraplnf("An email has been sent to '%s' "
"with an unlock id", CH(d)->pcdata->email);
CH(d)->println("Download the email and type in the code.");
return;
}
if(!str_cmp("change",argument)){
replace_string(CH(d)->pcdata->email,"");
CH(d)->printf("`=j%s`c", creation_titlebar("CHANGE EMAIL ADDRESS"));
CH(d)->wrapln(
" You need to key in a new email address for your character. Then the mud "
"will email you an unlock key, with which you can unlock your character a single time "
"during the logon process.");
CH(d)->wrapln(
" The email address 9 times of out 10 will have to be a valid email accout "
"as part of either the isps domain or an email account on the server you "
"are connecting through... e.g. if you are connecting from "
"`c207-112-146.ipt.aol.com`c it is most likely that the email "
"address you enter must be something like `cusername@aol.com`c"
"`1 The email address you type in will not be publically available... "
"only being able to be seen by those who administer the mud.`1"
"Please type in your email address now:");
d->connected_state = CON_RECHECK_EMAIL;
return;
}
if(!str_cmp("delete",argument)){
sprintf(buf,"mv %s %s &", pfilename( CH(d)->name, CH(d)->pcdata->pfiletype), LOCKED_PFILES_DIR);
system(buf);
CH(d)->printf("%s has been deleted, disconnecting you now.`1",
CH(d)->name);
connection_close( d );
return;
}
if(!str_cmp(CH(d)->pcdata->unlock_id,argument)){
// correct code :)
sprintf(buf, "%s - unlocked by %s",
CH(d)->pcdata->unlock_id, d->remote_hostname);
#define validatedhost ch->act&W?"..":
// move the pfile if required
{
PFILE_TYPE pt=get_pfiletype(CH(d));
replace_string(CH(d)->pcdata->unlock_id, buf);
PFILE_TYPE newpt=get_pfiletype(CH(d));
if(pt!=newpt){
rename(pfilename(CH(d)->name,pt),
pfilename(CH(d)->name,newpt)); // move the file
}
CH(d)->pcdata->pfiletype=newpt;
save_char_obj(CH(d)); // resave pfile
}
CH(d)->wraplnf(
"`1%s has been unlocked and saved!!! well done, `1"
"[press Y to continue]`1 :)",CH(d)->name);
d->connected_state = CON_READ_MOTD;
return;
}else{ // incorrect code
CH(d)->wraplnf(
"`1`1The code '%s' is incorrect...`1"
"This character '%s' can only be accessed with the unlock code that was "
"automatically emailed to '%s'.`1`1If you have that unlock code enter it now, "
"otherwise there are a few options - type:`1"
"`=Cquit`c to be disconnected`1"
"`=Cdelete`c to remove %s`1"
"`=Cresend`c to have the unlock resent to '%s'`1"
"`=Cchange`c to change your email address.",
argument, CH(d)->name, CH(d)->pcdata->email, CH(d)->name, CH(d)->pcdata->email);
return;
}
}
/**************************************************************************/
void nannysup_email_check(connection_data *d, const char *argument)
{
if(!d->resolved && resolver_running){
write_to_buffer( d,"Resolving ip address, this can take up to 60 seconds... please wait.", 0);
d->connected_state = CON_RESOLVE_IP;
d->connected_state_pulse_counter=0;
return;
}
replace_string(CH(d)->pcdata->created_from,
FORMATF("%s(%s)", d->remote_ip,d->remote_hostname));
if(check_ban(d,BAN_EMAIL_REQ)){
CH(d)->printf("`=j%s`c", creation_titlebar("EMAIL VERFICATION REQUIRED"));
CH(d)->wrapln(
" It appears we have had problems at some stage with people that connect "
"from the isp or server you are connecting to us from. In the past the "
"only way to deal with these types of problem players was to ban all "
"connections from the ISP or server involved. This was obviously "
"not a long term solution to the problem so we have developed a system "
"that allows you to enter your email address in, and the mud will email "
"you an unlock key, with which you can unlock the character you are "
"creating either at the end of the creation process, or you will be "
"prompted for the unlock key when you next logon.");
CH(d)->wrapln(
" The email address 9 times of out 10 will have to be a valid email accout "
"as part of either the isps domain or an email account on the server you "
"are connecting through... e.g. if you are connecting from "
"`c207-112-146.ipt.aol.com`c it is most likely that the email "
"address you enter must be something like `cusername@aol.com`c"
"`1 The email address you type in will not be publically available... "
"only being able to be seen by those who administer the mud.`1"
"Please type in your email address now:");
d->connected_state = CON_GET_EMAIL;
}else{
nannysup_past_email_check(d,argument);
}
}
/**************************************************************************/
void nanny_recheck_email(connection_data *d, const char *argument)
{
int result;
char logbuf[MSL];
logf("Start handle_recheck_email");
if(IS_NULLSTR(argument)){
write_to_buffer(d,"An email address is required sorry.\r\n",0);
write_to_buffer(d,"Please type in your email address now:\r\n",0);
return;
}
CH(d)->printf("`=j%s`c", creation_titlebar("="));
logf("Going into check_recheck_email argument='%s'", argument);
result=check_email_ban(d, (char*)argument);
logf("Result = %d", result);
switch(result){
default:
bugf("handle_get_email(): unknown result of %d from check_email_ban()!",result);
do_abort(); // get a coredump and debug it
break;
case 0: // 0 accepted email, and id code emailed to them.
{
char unlockbuf[20];
sprintf(unlockbuf,"%X", number_range(0x100000,0xFFFFFF));
// Log the email addy and details to file
sprintf(logbuf,"%-13s from '%s' accepted email '%s', unlock = %s",
CH(d)->name, d->remote_hostname, argument, unlockbuf);
append_datetimestring_to_file( EMAILADDRESSES_FILE, logbuf);
// move the pfile if required
{
save_char_obj(CH(d));
PFILE_TYPE oldpt=get_pfiletype(CH(d));
replace_string(CH(d)->pcdata->unlock_id, unlockbuf);
email_descriptor_unlock_id(d);
PFILE_TYPE pt=get_pfiletype(CH(d));
if(oldpt!=pt){
rename(pfilename(CH(d)->name,oldpt),
pfilename(CH(d)->name,pt)); // move the file
CH(d)->pcdata->pfiletype=pt;
}
save_char_obj(CH(d)); // update the lock key in the pfile
}
CH(d)->wraplnf("An email has been sent to '%s' "
"with an unlock id.", CH(d)->pcdata->email);
}
nanny_read_motd(d,"");
break;
case 1: // 1 email rejected, they need another attempt.
// do nothing
sprintf(logbuf,"%-13s from '%s' rejected email '%s'",
CH(d)->name, d->remote_hostname, argument);
append_datetimestring_to_file( EMAILADDRESSES_FILE, logbuf);
break;
case 2: // 2 if they should be disconnected
connection_close(d);
break;
}
logf("End of handle_get_email()");
}
/**************************************************************************/
// find the vnum players start in
int get_startvnum(char_data *ch)
{
if(IS_IRC(ch) && get_room_index(ROOM_VNUM_STARTIRC)){
return ROOM_VNUM_STARTIRC;
}
if(get_room_index(ROOM_VNUM_STARTTELNET)){
return ROOM_VNUM_STARTTELNET;
}
return ROOM_VNUM_OOC;
};
/**************************************************************************/
void do_save_gamesettings(char_data *ch, char *);
//void do_outfit( char_data *ch, char *);
/**************************************************************************/
void nanny_read_motd(connection_data *d, char *)
{
char_data *ch = d->character;
char buf[MSL];
char automaticbuf[MSL];
BAN_DATA *pban;
int sn;
if(ch->pcdata == NULL || ch->pcdata->pwd[0] == '\0')
{
write_to_buffer( d, "Warning! Null password!\r\n",0 );
write_to_buffer( d, "Please report old password with bug.\r\n",0);
write_to_buffer( d,
"Type 'password null <new password>' to fix.\r\n",0);
}
reset_char(ch);
if(!IS_NULLSTR(ch->pcdata->unlock_id) &&
str_len(ch->pcdata->unlock_id)==6){
CH(d)->printf("`1`=j%s`c", creation_titlebar("UNLOCK CODE REQUIRED"));
if(d->newbie_creating){
save_char_obj(ch);
ch->wraplnf(
"An unlock code for %s was automatically emailed to %s earlier during "
"the character creation process. This code is now "
"required for the one time unlocking of %s. "
"Your characters file has been saved, so if the email has not arrived yet "
"you can type `=Cquit`c now to disconnect, and then login later after you "
"have the code for unlocking.`1`1Enter your unlock code or type `=Cquit`c:",
ch->name, ch->pcdata->email, ch->name);
}else{
ch->wraplnf(
"This character '%s' can only be accessed with the unlock code that was "
"automatically emailed to '%s'.`1`1If you have that unlock code enter it now, "
"otherwise there are a few options, type `=Cquit`c to be disconnected, "
"`=Cdelete`c to remove %s, `=Cresend`c to have the unlock resent to '%s'"
"`=Cchange`c to change your email address.",
ch->name, ch->pcdata->email, ch->name, ch->pcdata->email);
}
d->connected_state = CON_ENTER_UNLOCK_ID;
return;
}
pban=check_ban(d,BAN_EMAIL_REQ);
if(pban){
logf("quick check '%s'", ch->pcdata->email);
if(IS_NULLSTR(ch->pcdata->email)){
CH(d)->printf("`=j%s`c", creation_titlebar("EMAIL VERFICATION REQUIRED"));
CH(d)->wrapln(
" Since you created your character it appears we have had problems with "
"with players that that connect from the isp or server you are connecting to us from. "
"In the past the only way to deal with these types of problem players was to ban all "
"connections from the ISP or server involved. This was obviously "
"not a long term solution to the problem so we have developed a system "
"that allows you to enter your email address in, and the mud will email "
"you an unlock key, with which you can unlock your character a single time "
"during the logon process.");
CH(d)->wrapln(
" The email address 9 times of out 10 will have to be a valid email accout "
"as part of either the isps domain or an email account on the server you "
"are connecting through... e.g. if you are connecting from "
"`c207-112-146.ipt.aol.com`c it is most likely that the email "
"address you enter must be something like `cusername@aol.com`c"
"`1 The email address you type in will not be publically available... "
"only being able to be seen by those who administer the mud.`1"
"Please type in your email address now:");
d->connected_state = CON_RECHECK_EMAIL;
return;
}else{ // they have already typed their email at some stage earlier
// check that is it still valid
int result=check_email_ban(d, ch->pcdata->email);
switch(result){
default:
bugf("nanny_read_motd(): unknown result of %d from check_email_ban()!",result);
do_abort(); // get a coredump and debug it
break;
case 0: // 0 still accepted email, do nothing
break;
case 1: // 1 email rejected since they last logged on
CH(d)->printf("`=j%s`c", creation_titlebar("EMAIL VERFICATION REQUIRED"));
CH(d)->wraplnf(
" It appears we have had problems with with players that that connect from "
"the isp or server you are connecting to us from. "
"Your email address that you typed in is no longer accepted because the restrictions "
"on email addresses from your ISP has been increased. As a result you will need "
"to enter a different email address than '%s'", ch->pcdata->email);
CH(d)->wrapln(
" The email address 9 times of out 10 will have to be a valid email accout "
"as part of either the isps domain or an email account on the server you "
"are connecting through... e.g. if you are connecting from "
"`c207-112-146.ipt.aol.com`c it is most likely that the email "
"address you enter must be something like `cusername@aol.com`c"
"`1 The email address you type in will not be publically available... "
"only being able to be seen by those who administer the mud.`1"
"Please type in your email address now:");
d->connected_state = CON_RECHECK_EMAIL;
return;
case 2: // 2 if they should be disconnected - currently not used by check_email_ban()
connection_close(d);
return;
}
}
}
// do multilogging checks
replace_string(ch->remote_ip_copy,d->remote_ip);
if(!HAS_CONFIG(ch,CONFIG_IGNORE_MULTILOGINS)){
for(char_data* pch=player_list; pch; pch=pch->next)
{
if(!HAS_CONFIG(pch,CONFIG_IGNORE_MULTILOGINS)){
if(!strcmp(ch->remote_ip_copy, pch->remote_ip_copy)){
d->multiple_logins=true;
if(TRUE_CH(pch)->desc){
TRUE_CH(pch)->desc->multiple_logins=true;
}
};
}
};
if(d->multiple_logins){
// notify wiznet
multilog_alertf(ch, "`YPossible multilog by `c%s `Y(%s)",
ch->name, ch->remote_ip_copy);
}
}
// add them to the player_list
ch->next_player = player_list;
player_list = ch;
// add them to the character list
ch->next = char_list;
char_list = ch;
// safety check they have at least 0 karns
if(ch->pcdata->karns<0){
check_death_update();
return;
}
ch->wraplnf("`1Welcome to %s. Enjoy your stay and try to leave smiling.", MUD_NAME);
if (double_exp)
{
ch->printlnf( "\n\r`mCurrently, a `MDOUBLE-XP BONUS`m is in affect!`x" );
//return;
}
if(d->newbie_creating){
info_broadcast(ch, "Welcome %s, the newest traveler to this realm!", ch->name);
d->newbie_creating=false;
}
ch->beginning_remort=0;
d->connected_state = CON_PLAYING;
// newbie starting out
if(ch->level == 0 )
{
// setting recall_vnum to the race recall
int start_room;
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;
// allocate a new players starting amounts - Daos, Oct03
ch->train = game_settings->newbie_start_train; // default 5
ch->practice = game_settings->newbie_start_practice; // default 10
ch->silver = game_settings->newbie_start_silver; // default 100
ch->gold = game_settings->newbie_start_gold; // default 0
// mark most of the notes and ideas etc as read
ch->pcdata->last_note = current_time-21600; // 6 hours
ch->pcdata->last_idea = current_time-21600;
ch->pcdata->last_penalty= current_time;
ch->pcdata->last_news = current_time-172800; // 2 days
ch->pcdata->last_changes= current_time-172800;
if(get_obj_index(OBJ_VNUM_WORLD_MAP)) // load world map if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_WORLD_MAP)),ch);
if(get_obj_index(OBJ_VNUM_NEWBIE_GUIDE )) // load newbie guide if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_NEWBIE_GUIDE)),ch);
/*if(!GAMESETTING2(GAMESET2_DONT_AUTOOUTFIT_ON_NEWBIE_LOGIN)){
do_outfit(ch,"");
}*/
/* // not supported at this stage
if(GAMESETTING2(GAMESET2_NEWBIES_GET_ALL_MAPS)){
if(get_obj_index(OBJ_VNUM_EVIL_CITY_MAP)){ // load main evil city map if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_EVIL_CITY_MAP)),ch);
}
if(get_obj_index(OBJ_VNUM_GOOD_CITY_MAP)){ // load main good city map if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_GOOD_CITY_MAP)),ch);
}
}else{
if(race_table[ch->race]->recall_room==ROOM_VNUM_EVIL_RECALL)
{ // evil city
if(get_obj_index(OBJ_VNUM_EVIL_CITY_MAP)){ // load main evil city map if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_EVIL_CITY_MAP)),ch);
}
}
else // good city
{
if(get_obj_index(OBJ_VNUM_GOOD_CITY_MAP)){ // load main good city map if it exists
obj_to_char(create_object(get_obj_index(OBJ_VNUM_GOOD_CITY_MAP)),ch);
}
}
}
*/
// give them their races newbie map
if(race_table[ch->race]->newbie_map_vnum){
if(get_obj_index(race_table[ch->race]->newbie_map_vnum)){
obj_to_char(create_object(get_obj_index(race_table[ch->race]->newbie_map_vnum)),ch);
}
}
// sending newbies to different starting locations based on connection
start_room = get_startvnum(ch);
if(get_room_index(start_room)!=NULL){
char_to_room( ch, get_room_index(start_room));
}else{
ch->printf( "BUG: the starting room for you city "
"doesn't exist (room number %d).\r\n", start_room);
bugf("BUG: the starting room for you city "
"doesn't exist (room number %d).\r\n", start_room);
if(get_room_index(ROOM_VNUM_LIMBO)==NULL){
bugf("BUG: get_room_index(ROOM_VNUM_LIMBO)==NULL"
"ROOM_VNUM_LIMBO = %d! Saving game settings, change it in there.\r\n", ROOM_VNUM_LIMBO);
do_save_gamesettings(NULL, "");
exit_error( 1 , "nanny_read_motd", "missing limbo!");
}
char_to_room( ch, get_room_index(ROOM_VNUM_LIMBO));
}
ch->println("\r\n");
}else if(ch->in_room){
char_to_room( ch, ch->in_room );
}else{
ROOM_INDEX_DATA *target_room= get_room_index(race_table[ch->race]->recall_room);
if(!target_room){
bugf("nanny_read_motd(): Couldn't find room %d to put player in "
"(as per race_table[ch->race]->recall_room)... putting them in limbo instead.",
race_table[ch->race]->recall_room);
target_room= get_room_index( ROOM_VNUM_LIMBO );
}
char_to_room(ch, target_room);
}
if(!GAMESETTING2(GAMESET2_NO_SECOND_SKILL_REQUIRED)){
if(get_eq_char(ch, WEAR_SECONDARY) && !IS_NPC(ch) && ch->get_skill(gsn_second)<1){
logf("removing second weapon from %s - doesn't have the skill to use it", ch->name);
unequip_char( ch, get_eq_char(ch, WEAR_SECONDARY));
}
}
// automatically turn on their IC object restrictions
SET_CONFIG(ch,CONFIG_NAMES_BEFORE_SHORT);
SET_CONFIG(ch, CONFIG_OBJRESTRICT);
if(IS_SET(ch->act,PLR_AUTOMAP)){
SET_CONFIG(ch,CONFIG_AUTOMAP);
REMOVE_BIT(ch->act,PLR_AUTOMAP);
}
// conversion to comm field
if(IS_SET(ch->act, PLR_SPECIFY_SELF)){
SET_BIT(ch->comm,COMM_AUTOSELF);
REMOVE_BIT(ch->act, PLR_SPECIFY_SELF);
}
/*********************************************
* turn on all their channels automatically *
*********************************************/
automaticbuf[0]='\0';
// quiet channels - turn off
if(HAS_CHANNELOFF(ch, CHANNEL_QUIET))
{
sprintf(buf,"Quiet mode has been automatically removed.\r\n");
strcat(automaticbuf,buf);
REMOVE_CHANNELOFF(ch, CHANNEL_QUIET);
}
// OOC channel turn on/off depending on nochannel status
if(IS_SET(ch->comm, COMM_NOCHANNELS))
{
sprintf(buf, "`COOC channel has been automatically turned OFF.\r\n");
strcat(automaticbuf,buf);
SET_CHANNELOFF(ch, CHANNEL_OOC);
}
else{
if(HAS_CHANNELOFF(ch, CHANNEL_OOC))
{
sprintf(buf, "`COOC channel has been automatically turned ON.\r\n");
strcat(automaticbuf,buf);
REMOVE_CHANNELOFF(ch, CHANNEL_OOC);
}
if(HAS_CHANNELOFF(ch, CHANNEL_CHAT))
{
sprintf(buf, "`CCHAT channel has been automatically turned ON.\r\n");
strcat(automaticbuf,buf);
REMOVE_CHANNELOFF(ch, CHANNEL_CHAT);
}
}
// Q/A channel turn on
if(HAS_CHANNELOFF(ch, CHANNEL_QA))
{
sprintf(buf, "`gQ/A channel has been automatically turned ON.\r\n");
strcat(automaticbuf,buf);
REMOVE_CHANNELOFF(ch, CHANNEL_QA);
}
// Newbie channel turn on
if(HAS_CONFIG( TRUE_CH(ch), CONFIG_NONEWBIE ))
{
sprintf(buf, "`SNewbie channel has been automatically turned ON.\r\n");
strcat(automaticbuf,buf);
REMOVE_CONFIG( TRUE_CH(ch), CONFIG_NONEWBIE );
}
// AFK turn off
if(IS_SET(ch->comm,COMM_AFK))
{
sprintf(buf, "`MAFK mode has been automatically turned OFF.\r\n");
strcat(automaticbuf,buf);
REMOVE_BIT(ch->comm,COMM_AFK);
}
if(ch->level>=LEVEL_IMMORTAL && IS_SET(ch->comm, COMM_NEWBIE_SUPPORT)){
ch->println("Removed your newbie support status as immortals always helps newbies ;)");
REMOVE_BIT(ch->comm, COMM_NEWBIE_SUPPORT);
}
// dont allow levels or trust greater than ABSOLUTE_MAX_LEVEL
if(ch->level>ABSOLUTE_MAX_LEVEL)
{
ch->level= LEVEL_IMMORTAL;
}
if(ch->trust>ABSOLUTE_MAX_LEVEL)
{
ch->trust= LEVEL_IMMORTAL;
}
// turn on imm things
if(ch->level >= LEVEL_IMMORTAL )
{
// turn wizi on if desired
if(HAS_CONFIG2(ch, CONFIG2_AUTOWIZILOGIN) && !INVIS_LEVEL(ch))
{
sprintf(buf, "`YYou have been made wizi %d automatically.\r\n",
LEVEL_IMMORTAL );
strcat(automaticbuf,buf);
ch->invis_level=LEVEL_IMMORTAL;
}
// turn whoinvis on if desired
if(HAS_CONFIG2(ch, CONFIG2_AUTOWHOINVISLOGIN)
&& IS_SET(TRUE_CH(ch)->comm, COMM_WHOVIS))
{
REMOVE_BIT(TRUE_CH(ch)->comm, COMM_WHOVIS);
sprintf( buf,"`rYou have been made whoinvis automatically.\r\n");
strcat(automaticbuf,buf);
}
// IMMTALK turn on
if(HAS_CHANNELOFF(ch, CHANNEL_IMMTALK)){
sprintf(buf,"`=IImmortal channel has been automatically turned ON.\r\n");
strcat(automaticbuf,buf);
REMOVE_CHANNELOFF(ch, CHANNEL_IMMTALK);
}
{
for(int ti=0; ti<4; ti++){
if(!IS_SET(ch->wiznet[ti],WIZ_ON) && IS_SET(ch->wiznet[ti],WIZ_AUTOON) )
{
switch(ti){
case 0: sprintf(buf, "Immwiznet autoactivated.\r\n"); break;
case 1: sprintf(buf, "Wiznet autoactivated.\r\n"); break;
case 2: sprintf(buf, "Wiznet2 autoactivated.\r\n"); break;
case 3: sprintf(buf, "Wiznet3 autoactivated.\r\n"); break;
}
strcat(automaticbuf,buf);
SET_BIT(ch->wiznet[ti],WIZ_ON);
}
}
}
}
strcat(automaticbuf,"`c");
/******************************************************
* end of turning on all their channels automatically *
******************************************************/
// tell them about ircwhite and irc colour modes if appropriate
if(IS_NEWBIE(ch) && IS_IRC(ch)){
ch->println("NOTE: You can change between black and white backgrounds by typing:");
ch->println(" `=Ccolour mode ircwhite`c and `=Ccolour mode irc`c.");
}
attach_know(ch); // setups ch->know stuff
assertp(ch->know);
if(!GAMESETTING2(GAMESET2_DONT_DISPLAY_WHO_4_LOGIN)){
// give autowho to everyone
// - doesn't show imms automatically though for morts
do_who( ch, "-noimm4morts" );
}
// update their msp settings
msp_update_char(ch);
ch->printf(automaticbuf);
check_offline_letgain(ch);
// Reset lastused on all everything for imms
if(ch->level>=LEVEL_IMMORTAL){
for( sn = 0; sn < MAX_SKILL; sn++ ){
if(!IS_NULLSTR(skill_table[sn].name)){
ch->pcdata->last_used[sn] = 0;
}
}
}
if(ch->pet){
if(ch->pet->in_room){
char_to_room(ch->pet,ch->pet->in_room); // restore to room they left from
}else{
char_to_room(ch->pet,ch->in_room); // restore to room the master
}
act("$n has entered the realm.",ch->pet,NULL,NULL,TO_ROOM);
}
if(GAMESETTING5(GAMESET5_DEDICATED_PKILL_STYLE_MUD))
{
char_data *victim=ch;
int newlevel=UMAX(number_range(LEVEL_HERO-10,LEVEL_HERO-1),ch->level);
ch->pcdata->p9999kills=ch->pcdata->p9999defeats=0;
if(ch->level<10){
ch->pksafe=10;
}
if(!IS_LETGAINED(ch)){
SET_BIT(ch->act,PLR_CAN_ADVANCE);
ch->println("`GYOU HAVE BEEN AUTOMATICALLY LETGAINED!!!.`c\r\n");
};
if(ch->level<LEVEL_IMMORTAL ){
int iLevel;
int temp_prac;
ch->pknoquit=4;
ch->pksafe=3;
ch->printf("`BAUTOMATICALLY SETTING YOU TO LEVEL %d!!!`c", newlevel);
if(victim->level<newlevel){
temp_prac = victim->practice;
victim->level = 1;
victim->exp = exp_per_level(victim,victim->pcdata->points);
victim->max_hit = 10;
victim->max_mana = 100;
victim->max_move = 100;
victim->practice = 0;
victim->hit = victim->max_hit;
victim->mana = victim->max_mana;
victim->move = victim->max_move;
advance_level( victim );
victim->practice = temp_prac;
}
for( iLevel = ch->level ; iLevel < newlevel; iLevel++ )
{
ch->level += 1;
advance_level( ch);
}
ch->exp = exp_per_level(ch,ch->pcdata->points)
* UMAX( 1, ch->level );
}
{
ch->println("`GSETTING ALL MORTAL SKILLS TO 101%.`c\r\n");
for( sn = 0; !IS_NULLSTR(skill_table[sn].name); sn++ )
{
if(IS_SET(skill_table[sn].flags,SKFLAGS_NO_GAIN)){
continue;
}
if(IS_SPELL(sn)
&& !IS_SET(skill_table[sn].flags, SKFLAGS_LEVEL_SPGAIN)
&& !IS_SET(skill_table[sn].flags, SKFLAGS_STUDY_SPGAIN))
{
continue;
}
// check if no class can get it
bool a_class_can_get=false;
{
int cl;
for(cl=0; !IS_NULLSTR(class_table[cl].name); cl++){
if(class_table[cl].creation_selectable){
if(skill_table[sn].rating[cl] > 0
&& skill_table[sn].skill_level[cl]< LEVEL_IMMORTAL
&& skill_table[sn].skill_level[cl]>0)
{
a_class_can_get=true;
}
}
}
}
if(!a_class_can_get){
continue;
}
victim->pcdata->learned[sn] = 101;
}
}
reset_char(victim);
victim->max_hit+=number_range(40,200);
victim->max_mana+=number_range(40,200);
victim->max_move+=number_range(40,200);
victim->gold+=number_range(40,400);
// login restore
victim->subdued = false;
if(!IS_NPC(victim) && victim->pcdata->tired!=-1)
{
victim->pcdata->tired=0;
}
affect_strip(victim,gsn_plague);
affect_strip(victim,gsn_poison);
affect_strip(victim,gsn_blindness);
affect_strip(victim,gsn_sleep);
affect_strip(victim,gsn_curse);
affect_strip(victim,gsn_cause_fear);
affect_strip(victim,gsn_fear_magic);
victim->hit = victim->max_hit;
victim->mana = victim->max_mana;
victim->move = victim->max_move;
victim->pcdata->tired=0;
update_pos( victim);
ch->println( "`MYOU HAVE BEEN AUTOMATICALLY BOOSTED AND RESTORED!!!.`c");
ch->printlnf( "`YYOU ARE PK SAFE FOR %d MINUTES!!!.`c",ch->pksafe);
// announce their arrival
if(!IS_IMMORTAL(ch)){
pkill_broadcast("%s has entered the realm of death! [Pk=0.Pd=0,L=%d]",
ch->name, ch->level);
}
}
// automatically letgain remorted players
if(ch->remort>0 && !IS_LETGAINED(ch)){
SET_BIT(ch->act,PLR_CAN_ADVANCE);
ch->println("`GYOU HAVE BEEN AUTOMATICALLY LETGAINED!!!.`c\r\n");
}
ch->mxp_send_init();
do_look( ch, "brief" );
act( "$n has entered the realm.", ch, NULL, NULL, TO_ROOM );
//info_broadcast(ch, "%s has entered the realm.", ch->name);
if(IS_IRCCON(d)){
sprintf(buf, "`B%s has joined the game via IRC. [%s] (lvl %d, remort %d)`c",
ch->name, ch->desc?ch->desc->remote_hostname:"no_descriptor",
ch->level, ch->remort);
}else{
sprintf(buf, "%s has joined the game via telnet. [%s] (lvl %d, remort %d)",
ch->name, ch->desc?ch->desc->remote_hostname:"no_descriptor",
ch->level, ch->remort);
}
wiznet(buf,ch,NULL, WIZ_LOGINS,0,UMIN(get_trust(ch), MAX_LEVEL));
if(ch->level <= 10 && !HAS_CONFIG( ch, CONFIG_NONEWBIE ))
nsupport_newbie_alert( ch, true );
laston_login(ch); // record the time the character logged on
do_unread(ch,"");
// display a legal notice about olc creation
if(HAS_SECURITY(ch, 1) && !HAS_CONFIG2(ch, CONFIG2_READ_BUILDER_LEGAL)){
display_legal_message(ch);
}
// tell MAX_LEVEL to set up their security.
if(IS_TRUSTED(ch, MAX_LEVEL) && GET_SECURITY(ch)<1){
ch->titlebar("INCREASE YOUR OLC SECURITY?");
ch->wraplnf("`cYour olc security is currently set to 0, you need a security "
"of %d to edit the game settings (by typing `=Cgameedit confirm`c). "
"You can increase your olc security to 9 (the maximum) by typing "
"`=Cset char self security 9`c", GAMEEDIT_MINSECURITY);
ch->wraplnf("`cHint: to list all the olc editors available, type `=Ccommand edit`c "
"for the ones commonly used by builders and `=Cwiz edit`c for the "
"immortal/administrative editors.");
ch->titlebar("`S[The above message disappears once you have a security higher than 0]");
}
// tell users to upgrade their mud client if they have one with known issues
if(!GAMESETTING2(GAMESET2_NO_MSG_ABOUT_OLD_MUDCLIENTS)){
if(ch->desc && IS_SET(ch->desc->flags, CONNECTFLAG_MXP_SECURE_PREFIX_EACH_LINE) ){
ch->titlebar("THERE ARE KNOWN MXP ISSUES WITH YOUR CURRENT MUD CLIENT");
ch->wrapln("`cThis mud makes heavy use of MXP... there are known "
"bugs in your particular mud client (MXP and MCCP). It is "
"recommended that you update your mud client if an update "
"is available, or try another "
"client - such as `cMuClient`c (available from "
"`Bhttp://www.muclient.com`c)`1`1Alternatively if you notice "
"unexpected output on your screen while using this client you may "
"disable MXP and MCCP (view menu -> preferences -> "
"general -> mxp) then restart the client.");
ch->titlebar("");
}
}
// message to tell mushclient users to turn off the forced link colour
if(ch->desc
&& !IS_NULLSTR(ch->desc->mxp_options)
&& strstr(ch->desc->mxp_options, "use_custom_link_colour=1")){
ch->titlebar("MXP RECOMMENDATION");
ch->println("Turn 'use custom link colour' mxp option off in your mud client!");
ch->wrapln("`cThis mud makes heavy use of colours in MXP links (especially in olc)... "
"currently your mud client is configured to ignore the muds "
"colour for links and has the 'use custom link colour' mxp option on..."
" It is strongly recommended that you turn this option off for a better "
"mudding experience. (Try Ctrl+Alt+U to do this).");
ch->titlebar("");
}
// mobprog login trigger
mp_login_trigger( ch);
// offline moot kickin
check_pending_moot(ch);
// record their entry into the game into their plog if they have one
if (!IS_NPC(ch) && IS_SET(ch->act, PLR_LOG)){
append_playerlog( ch,
FORMATF("%s has entered the game. (left level %d), room=%d, lasticroom=%d",
ch->name, ch->level,
ch->in_room?ch->in_room->vnum:0,
ch->last_ic_room?ch->last_ic_room->vnum:0));
}
}
/**************************************************************************/
void nanny_get_name(connection_data *d, char *argument)
{
char_data *ch;
bool pfile_loaded_okay;
char buf[MSL];
if(IS_NULLSTR(argument)){
write_to_buffer( d,
"You can't have a blank name, type 'new' to create a new character,\r\n"
"'quit' to disconnect, or type your characters name - try again.\r\n", 0);
write_to_buffer(d, LOGIN_PROMPT, 0);
return;
}
if(!str_cmp(argument,"quit")){
connection_close( d );
return;
}
if(!str_cmp(argument,"dawnftp") || !str_cmp(argument,"mudftp")){
logf("DawnFTP connection %d starting.", d->connected_socket);
// 00 code indicates unsupported
// 01 code indicates continue
write_to_buffer(d, "\n:DAWNFTP:01 v1:transfering to mudftp authentication state.\n", 0);
d->connected_state=CON_FTP_AUTH;
return;
}
// check for invalid characters
if(strstr(".", argument) || strstr("\\", argument)
|| strstr("/", argument)){
write_to_buffer( d, "Invalid characters in name, "
"try again.\r\nName:", 0);
return;
}
argument=capitalize(argument);
pfile_loaded_okay= load_char_obj( d, argument );
ch = d->character;
d->newbie_creating = false;
// do checks on what was read in
// check for multiple pfiles found
if(ch->pcdata->pfiletype==PFILE_MULTIPLE){
ch->wraplnf("For some reason multiple copies of pfiles "
"for '%s' found... to avoid loading the incorrect copy, your pfile "
"can not be loaded. Create a new character and then write a note to "
"admin once in the game.", ch->name);
ch->print("Name:");
return;
}
// check for levels/trust/security etc
if(pfile_loaded_okay)
{
int maxsecurity=0;
int maxtrust=0;
int maxlevel=LEVEL_HERO;
switch(ch->pcdata->pfiletype){
case PFILE_LOCKED:
break;
case PFILE_NORMAL:
break;
case PFILE_BUILDER:
maxsecurity=9;
break;
case PFILE_TRUSTED:
maxsecurity=9;
maxtrust=MAX_LEVEL;
break;
case PFILE_IMMORTAL:
maxsecurity=9;
maxtrust=ABSOLUTE_MAX_LEVEL;
maxlevel=ABSOLUTE_MAX_LEVEL;
break;
default:
break;
}
if(ch->pcdata->security>maxsecurity){
if(maxsecurity==9){
maxsecurity=8;
}
ch->wraplnf("`RNOTICE: Your player file was loaded from a directory that "
"limits olc security. Your olc security was read in being higher than allowed, "
"therefore your security has been changed from %d to %d!`c",
ch->pcdata->security, maxsecurity);
ch->pcdata->security=maxsecurity;
}
if(ch->trust>maxtrust){
if(maxtrust==ABSOLUTE_MAX_LEVEL){
maxtrust=MAX_LEVEL;
}
ch->wraplnf("`RNOTICE: Your player file was loaded from a directory that "
"limits trust level. Your trust was read in being higher than allowed, "
"therefore your trust has been changed from %d to %d!`c",
ch->trust, maxtrust);
ch->trust=maxtrust;
}
if(ch->level>maxlevel){
if(maxlevel==ABSOLUTE_MAX_LEVEL){
maxlevel=MAX_LEVEL;
}
ch->wraplnf("`RNOTICE: Your player file was loaded from a directory that "
"limits your level to that of a mortal. Your level was read in as being higher "
"than allowed, therefore your level has been changed from %d to %d!`c",
ch->level, maxlevel);
ch->level=maxlevel;
}
}
if(IS_SET(ch->act, PLR_DENY)){
sprintf( log_buf, "Denying access to %s@%s.", argument, d->remote_hostname );
log_string( log_buf );
wiznet(log_buf,NULL,NULL,WIZ_SECURE,0,get_trust(ch));
d->write("You are denied access!\r\n", 0 );
if(d){
if(IS_IRCCON(d)){
sprintf( log_buf, "DENIED PLAYER DROPPED (nanny)\r\n"
"was %s@%s (connected via IRC). (socket = %d)",
ch->name, d->remote_hostname, d->connected_socket );
}else{
sprintf( log_buf, "DENIED PLAYER DROPPED (nanny)\r\n"
"was %s@%s (socket = %d)",
ch->name, d->remote_hostname, d->connected_socket);
}
wiznet(log_buf,NULL,NULL,WIZ_SECURE,0,get_trust(ch));
log_string(log_buf);
}
connection_close(d);
return;
}
ch->mxp_send_init();
if(check_connection_ban(d)){
return;
}
if(check_reconnect( d, argument, false )){
pfile_loaded_okay= true;
}else{
if(GAMESETTING(GAMESET_PLAYER_LOCKED)){
write_to_buffer( d, "\r\nThe game is playerlocked, only the administration can currently connect.\r\n", 0 );
if(!IS_IMMORTAL(ch) && !ch->host_validated && !d->ident_confirmed){
connection_close( d );
return;
}
write_to_buffer( d, "\r\n\r\nIF THE ADMIN ARE WANTING PLAYERS TO LOG INTO THE GAME, THEY NEED TO UNPLAYERLOCK THE GAME!\r\n\r\n", 0 );
}
}
if(pfile_loaded_okay){
if(ch->pcdata && ch->pcdata->colourmode){
d->colour_mode=ch->pcdata->colourmode;
}else{
d->colour_mode=CT_NOCOLOUR;
}
if(!str_cmp( "-", ch->pcdata->pwd ))
{
write_to_buffer( d, "Your password has been wiped...\r\n", 0 );
write_to_buffer( d, "Please set your password using the password command, then relogin.\r\n", 0 );
write_to_buffer( d, "Syntax: password - <new password>.\r\n", 0 );
d->connected_state = CON_READ_MOTD;
}
else
{
// Old player
if(HAS_MXPDESC(d)){
write_to_buffer( d, mxp_tagify("`cCharacter Password:`c <PASSWORD>"), 0 );
}else{
write_to_buffer( d, "`cCharacter Password:`c ", 0 );
}
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}else{
write_to_buffer( d, echo_off_str, 0 );
}
d->connected_state = CON_GET_OLD_PASSWORD;
}
return;
}
else
{
if(!str_cmp("new", argument)){
if(!d->ident_confirmed){
if(GAMESETTING(GAMESET_PLAYER_LOCKED)){
write_to_buffer( d, "Sorry, the game is currently playerlocked, no new players can be created at this point in time.\r\n", 0 );
connection_close( d );
return;
}
if(GAMESETTING(GAMESET_NEWBIE_LOCKED)){
write_to_buffer( d, "Athens is only available for building, coding and light player testing.\r\n", 0 );
write_to_buffer( d, " contact the owner at: hera_of_athens@yahoo.com \r\n", 0);
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer(d,"\r\n", 2);
}
return;
}
logf("Socket %d (%s) is considering making a new character",
d->connected_socket, d->remote_hostname);
}
write_to_buffer( d, "Do you really want to create a new character? (Y or N)", 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0);
}
d->connected_state = CON_CONFIRM_CREATING_NEW;
return;
}
// pfile not found for playername
sprintf( buf,
"I don't recognise the name '%s', if you wish to create a \r\n"
"character called '%s' type 'new' (without the quotes).\r\n",
argument, argument);
write_to_buffer( d, buf, 0);
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer(d,"\r\n", 2);
}
// recycle the memory we just allocated
free_char(d->character);
d->character = NULL;
return;
}
}
/**************************************************************************/
void nanny_get_automap(connection_data *d, char *argument)
{
switch( *argument )
{
default:
write_to_buffer(d,"Please type Yes or No ",0);
return;
case 'y' : case 'Y':
SET_BIT(d->character->act,PLR_AUTOMAP);
d->character->println("Automap activated!\r\n");
break;
case 'n' : case 'N':
REMOVE_BIT(d->character->act,PLR_AUTOMAP);
d->character->println("Automap not activated.\r\n");
break;
}
// start class selection
connected_to_CON_REROLL_STATS(d);
return;
}
/**************************************************************************/
void begin_remort( char_data *oc);
/**************************************************************************/
void nannysup_process_correct_connect_password(connection_data *d)
{
char_data *ch = d->character;
// remort patch in here
if(ch->beginning_remort){
begin_remort(ch);
return;
}
if(IS_IRCCON(d)){
sprintf( log_buf, "%s@%s has connected via IRC. (socket=%d, lvl=%d)",
ch->name, d->remote_hostname, ch->desc->connected_socket, ch->level );
}else{
sprintf( log_buf, "%s@%s has connected. (socket=%d, lvl=%d)",
ch->name, d->remote_hostname, ch->desc->connected_socket, ch->level );
}
log_string( log_buf );
wiznet(log_buf,ch,NULL,WIZ_SITES,0, UMIN(get_trust(ch), MAX_LEVEL));
nanny_char_version_updates(ch);
if(ch->version>5 && ch->version!=0)
{
if(IS_IMMORTAL(ch) )
{
do_help( ch, "imotd" );
ch->hit_return_to_continue();
d->connected_state = CON_READ_IMOTD;
}
else
{
if(IS_IRCCON(d)){
do_help( ch, "irc-motd" );
}else{
do_help( ch, "motd" );
}
ch->hit_return_to_continue();
d->connected_state = CON_READ_MOTD;
}
}
else
{
if(ch->version==0)
{
int langsn=race_table[ch->race]->language->gsn;
if(langsn>0){
ch->pcdata->learned[langsn]=100;
}
ch->language=race_table[ch->race]->language;
ch->gen_data = new_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:\r\n",0);
do_skills(ch,"");
do_help(ch,"menu-choice");
d->connected_state = CON_GEN_GROUPS;
return;
}
ch->version=6;
connected_to_CON_GET_ALLIANCE(d);
return;
}
}
/**************************************************************************/
void nanny_get_old_password(connection_data *d, char *argument)
{
char_data *ch = d->character;
write_to_buffer( d, "\r\n", 2 );
if(ch->pcdata->overwrite_pwd){
write_to_buffer( d, "Your password has been wiped...\r\n", 0 );
write_to_buffer( d, "Please set your password using the password command, then relogin.\r\n", 0 );
write_to_buffer( d, "Syntax: password - <new password>.\r\n", 0 );
}else{
if(!is_valid_password(argument, ch->pcdata->pwd, d))
{
logf( "Socket %d (%s) got the password wrong for %s!",
ch->desc->connected_socket, ch->desc->remote_hostname, ch->name);
write_to_buffer( d, "Wrong password", 0 );
if(++d->wrong_password_count<3){
write_to_buffer( d, " - try again.\r\n", 0 );
write_to_buffer( d, "`cCharacter Password:`c ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}else{
write_to_buffer( d, echo_off_str, 0 );
}
return;
}else{
write_to_buffer( d, ".\r\n", 0 );
}
connection_close( d );
return;
}
}
logf("Socket %d (%s) got the password correct for %s",
ch->desc->connected_socket, ch->desc->remote_hostname, ch->name);
// automatically extract a ploaded player if they login while ploaded
{
char_data *t=pload_find_player_by_name(ch->name);
if(t){
logf("automatically extracting the ploaded player '%s' due to login.", ch->name);
pload_extract(NULL, t);
}
}
if(ch->version==0)
{
logf("Socket %d - char version = 0", ch->desc->connected_socket);
write_to_buffer( d, "Please remember to set your password when you finish creating.\r\n", 0 );
}
if(!IS_IRCCON(d)){
write_to_buffer( d, echo_on_str, 0 );
}
write_to_buffer( d, "\r\n", 0 );
// display the codebase advert
if(!GAMESETTING2(GAMESET2_DONT_DISPLAY_CODEBASE_4_LOGIN)){
ch->println(" `GThis mud is based on the Dawn of Time codebase`c");
}
// display last login info
if(!IS_NULLSTR(ch->pcdata->last_logout_site)){
char lastbuf[MSL];
sprintf(lastbuf, " You last logged in from %s\r\n"
" and logged out at %s",
ch->pcdata->last_logout_site,
(char *) ctime( &ch->pcdata->last_logout_time));
lastbuf[str_len(lastbuf)-1]='\0';
strcat(lastbuf, FORMATF("\r\n which was %s ago.\r\n\r\n",
short_timediff(ch->pcdata->last_logout_time, current_time)));
write_to_buffer( d, lastbuf, 0 );
}
if(check_playing(d,ch->name))
return;
if(check_reconnect( d, ch->name, true ) )
return;
if(ch->host_validated){
ch->print(validatedhost"...");
}else{
// process a connection password - if there is one
if(!IS_NULLSTR(game_settings->password_player_connect)
&& str_cmp(game_settings->password_player_connect, "-")
&& !IS_IMMORTAL(ch)){
ch->wrapln("There is currently a player connect password set which you must "
"enter in now before you can connect to the game`1Please enter the connection password:");
d->connected_state=CON_GET_CONNECT_PASSWORD;
return;
}
}
nannysup_process_correct_connect_password(d);
}
/**************************************************************************/
void nanny_break_connect(connection_data *d, const char *argument)
{
connection_data *d_old, *c_next;
char name[MIL];
strcpy(name, CH(d)?CH(d)->name:"???");
switch( *argument )
{
case 'y' : case 'Y':
logf("Socket %d (%s) to break connect (%s)",
d->connected_socket, d->remote_hostname, name);
for( d_old = connection_list; d_old != NULL; d_old = c_next )
{
c_next = d_old->next;
if(d_old == d || d_old->character == NULL)
continue;
if(str_cmp(name,d_old->original ?
d_old->original->name : d_old->character->name))
continue;
connection_close(d_old);
}
if(check_reconnect(d,name,true)){
return;
}
logf("Socket %d (%s) reconnect failed for %s",
d->connected_socket, d->remote_hostname, name);
write_to_buffer(d,"Reconnect attempt failed.\r\nName: ",0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
if(d->character != NULL ){
free_char( d->character );
d->character = NULL;
}
d->connected_state = CON_GET_NAME;
break;
case 'n' : case 'N':
sprintf( log_buf, "Socket %d (%s) decided not to force another (%s) off.",
d->connected_socket, d->remote_hostname, name);
log_string(log_buf);
write_to_buffer(d,"Name: ",0);
if(d->character){
free_char( d->character );
d->character = NULL;
}
d->connected_state = CON_GET_NAME;
break;
default:
write_to_buffer(d,"Please type Yes or No ",0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
break;
}
}
/**************************************************************************/
// send the name selection prompt to the new player
void nannysup_name_select_prompt(connection_data *d)
{
char_data *ch=d->character;
// ch->printlnf("Name selector commands: <1-%d>, list, help, requirements\r\n"
// "Enter your characters name or name selector command: ", profile_count);
if(IS_IRCCON(d)){
ch->println("");
}
}
/**************************************************************************/
void nannysup_begin_name_select(connection_data *d)
{
char_data *ch=d->character;
ch->lines += 15;
if(!codehelp(CH(d), "creation_name_requirements", false)){
ch->wrapln(
"\nThe first stage in creating a character is to come up with a name "
"for it. There are many things to consider when naming your character, "
"here are some requirement your character's name must meet:"
"`1"
"`1- Be creative. Do not give your character the name of another character"
"`1 you like in a fantasy book."
"`1- Do not give your char a descriptive name such as CoolGuy, SexyJane,"
"`1 WeaponMaster or GreatFighter."
"`1- Dont put titles in your name such as EmperorCrosash or LadyElbriana"
"`1- Do not put nouns, adjectives or adverbs. If a word has a meaning,"
"`1 keep it off your name. Examples: Slasher, TheShadow, RedDrac, Bloody."
"`1- Swear words and names from earthly religions are not allowed."
"`1- The administration reserve the right to change your name for any"
"`1 reason what so ever, and will most likely do so if could be in"
"`1 anyway disrespectful, or in violation of any of the above points."
"`1"
"`1Try to keep in mind the time period and theme for our mud. If you have "
"questions about choosing a name or why it might have been suggested that "
"change yours, any Newbie Support Technician can assist you."
"`1"
"`1Enter your character's name:`1");
}
ch->lines -= 15;
nannysup_name_select_prompt(d);
d->connected_state=CON_NAME_SELECT;
}
/**************************************************************************/
void nanny_name_select(connection_data *d, char *argument)
{
char_data *ch=d->character;
name_profile *nl;
name_confirmed=0;
// show help
if(!str_cmp("help", argument)){
ch->wrapln(
"The name selector gives you the option to type in a name you would "
"like to give the character you are creating or can be used to suggest "
"possible names you might like to consider."
"`1The names the selector generates are randomized sequences of letters "
"based on various naming profiles... these naming profiles give names of "
"a certain 'style'."
"`1"
"`1Name selector commands:"
"`1 '`=Chelp`c' shows this help screen."
"`1 '`=Crequirements`c' shows you the requirements your name must meet."
"`1 '`=Clist`c' will list the name profiles available."
"`1"
"`1The list command displays the title of a name profile and its number, "
"to see names generated with that particular profile simply type the "
"corresponding number and press enter. Because the system generates "
"random names from a profile, you can use a profile numerous times "
"with different names of simular style each time.");
nannysup_name_select_prompt(d);
return;
}
if(IS_NULLSTR(argument) || !str_prefix(argument, "requirements")){
nannysup_begin_name_select(d);
return;
}
if(d && d->ident_confirmed){
name_confirmed=1;
}
// list profiles
if(!str_cmp("list", argument)){
int count=0;
ch->printf("`=j%s`c", creation_titlebar("NAME GENERATOR PROFILES"));
for(nl=name_profiles_list; nl; nl=nl->next){
ch->printlnf("%2d> %s", ++count, nl->title);
}
ch->wrapln("`SNOTE: randomly generated names in some rare "
"situations will not meet the naming requirements.`c");
nannysup_name_select_prompt(d);
return;
}
// use a profile
if(is_number(argument)){
int count=0;
int profile_num=atoi(argument);
if(profile_num<1 || profile_num>profile_count){
ch->printlnf("Invalid profile number %d.", profile_num);
return;
}
for(nl=name_profiles_list; nl; nl=nl->next){
if(++count>=profile_num){
break;
};
}
int i;
ch->printf("`cName Generator");
for(i=0; i<60; i++){
ch->printf(" %-18s", capitalize(genname(nl)));
if(i%4==3){
ch->println("");
}
}
ch->println("");
ch->wrapln("`=cNOTE: randomly generated names in some rare situations "
"will not meet the naming requirements.`c");
nannysup_name_select_prompt(d);
return;
}
// *** A player has suggested a name - check it out
// check for invalid characters in name
if(strstr(".", argument) || strstr("\\", argument)
|| strstr(" ", argument) || strstr("/", argument)){
ch->wraplnf("Invalid letters name '%s' try another name (no spaces, fullstops "
"or slashes in your please, try another single word name.", argument);
nannysup_name_select_prompt(d);
return;
}
argument=capitalize(argument);
ch->wraplnf("Checking if the name '%s' is not currently used by another player "
"or monster, please wait...", argument);
// check for existing player with same name
PFILE_TYPE pt=find_pfiletype(argument);
ch->pcdata->pfiletype=pt;
if(pt!=PFILE_NONE){
ch->printlnf("The name '%s' is already in use. Try another name.", argument);
nannysup_name_select_prompt(d);
return;
}
// check if we can reject the name for other reasons
if(!check_parse_name( argument ) )
{
ch->printlnf("Sorry the name '%s' is unable to be used, try another.", argument);
nannysup_name_select_prompt(d);
return;
}
{ // dont allow duplicate names in creation
connection_data *dc;
for( dc = connection_list; dc; dc = dc->next )
{
if(d!=dc && dc->character && !str_cmp(dc->character->name, argument) )
{
logf("Socket %d (%s) had name %s rejected because another is creating with it",
d->connected_socket, d->remote_hostname, CH(d)->name);
ch->printlnf("Sorry someone else is currently creating using the name '%s', try another.", argument);
nannysup_name_select_prompt(d);
return;
}
}
}
replace_string(ch->name, argument);
ch->wraplnf("The name '%s' appears to be available for you to use
(assuming it meets "
"the naming requirements listed earlier)."
"`1Do you want to start creating a new character called '%s'?", argument, argument);
d->connected_state=CON_CONFIRM_NEW_NAME;
}
/**************************************************************************/
void nanny_confirm_new_name(connection_data *d, const char *argument)
{
char_data *ch=d->character;
switch( *argument )
{
case 'y': case 'Y':
if(count_creation_connections_per_hour(d)>2){
ch->wrapln("WARNING: We limit how many times you can create a character per hour!!!"
"`1You can only create a few more times this hour!");
}
ch->printlnf("`cWelcome %s! It is time for you to now pick a password.", ch->name);
ch->printf("`cPlease enter a new password for %s:`c %s",
ch->name, IS_IRCCON(d)?"\r\n":echo_off_str );
d->connected_state = CON_GET_NEW_PASSWORD;
break;
case 'n': case 'N':
logf("Socket %d (%s) decided not to make a new player.",
d->connected_socket, d->remote_hostname);
write_to_buffer( d, "`cOk, lets start from the very start again...\r\n", 0 );
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
free_char(d->character);
d->character = NULL;
d->connected_state = CON_GET_NAME;
break;
default:
write_to_buffer( d, "`cPlease type Yes or No ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
break;
}
}
/**************************************************************************/
void nanny_confirm_creating_new(connection_data *d, const char *argument)
{
char_data *ch=d->character;
switch( *argument )
{
case 'y': case 'Y':
d->newbie_creating= true;
// check for newbie bans
if(check_connection_ban(d))
break;
if(check_connection(d))
break;
// mark them as using the new colour code
if(ch->pcdata){
ch->pcdata->colour_code=COLOURCODE;
}
// process a connection password - if there is one
if(!IS_NULLSTR(game_settings->password_player_connect)
&& str_cmp(game_settings->password_player_connect, "-")
&& !IS_IMMORTAL(ch) && !ch->host_validated && !d->ident_confirmed){
ch->wrapln("There is currently a player connect password set which you must "
"entered to play. Before you can create a new character you need to enter "
"the connect password.`1Please enter the connection password:");
d->connected_state=CON_GET_CONNECT_PASS2CREATE;
return;
}else if(!IS_NULLSTR(game_settings->password_creation)
&& str_cmp(game_settings->password_creation, "-")
&& !ch->host_validated && !d->ident_confirmed){
ch->wrapln("There is currently a creation password set which you must "
"enter in now before creating a new character`1Please enter the creation password:");
d->connected_state=CON_GET_CREATION_PASSWORD;
}else{
nannysup_begin_name_select(d);
}
break;
case 'n': case 'N':
d->newbie_creating= false;
logf("Socket %d (%s) decided not to make a new player.",
d->connected_socket, d->remote_hostname);
write_to_buffer( d, "Ok, lets try again...\r\n", 0 );
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
free_char( d->character );
d->character = NULL;
d->connected_state = CON_GET_NAME;
break;
default:
write_to_buffer( d, "Please type Yes or No ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
break;
}
}
/**************************************************************************/
void nanny_get_connect_password_before_creating(connection_data *d, const char *argument)
{
char_data *ch=d->character;
assertp(game_settings->password_player_connect);
// correct creation password
if(!str_cmp(game_settings->password_player_connect, argument)){
if(!IS_NULLSTR(game_settings->password_creation)
&& str_cmp(game_settings->password_creation, "-")
&& !ch->host_validated && !d->ident_confirmed){
ch->printf("`=j%s`c", creation_titlebar("CREATION PASSWORD REQUIRED"));
ch->wrapln("There is also currently a creation password set which you must "
"enter in now before creating a new character`1Please enter the creation password:");
d->connected_state=CON_GET_CREATION_PASSWORD;
}else{
nannysup_begin_name_select(d);
}
return;
}
// wrong creation password
ch->wraplnf("Sorry, '%s' is not the connect password... you can't create a new "
"character at this point in time.", argument);
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
free_char( ch );
d->character = NULL;
d->connected_state = CON_GET_NAME;
}
/**************************************************************************/
void nanny_get_creation_password(connection_data *d, const char *argument)
{
char_data *ch=d->character;
assertp(game_settings->password_creation);
// correct creation password
if(!str_cmp(game_settings->password_creation, argument)){
ch->println("great, now lets get on with creating a character.");
nannysup_begin_name_select(d);
return;
}
// wrong creation password
ch->wraplnf("Sorry, '%s' is not the creation password... you can't create a new "
"character at this point in time.", argument);
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
free_char( ch );
d->character = NULL;
d->connected_state = CON_GET_NAME;
}
/**************************************************************************/
void nanny_get_connect_password(connection_data *d, const char *argument)
{
char_data *ch=d->character;
assertp(game_settings->password_player_connect);
// correct connect password
if(!str_cmp(game_settings->password_player_connect, argument)){
ch->println("great, now lets get on with creating a character.");
nannysup_process_correct_connect_password(d);
return;
}
// wrong creation password
ch->wraplnf("Sorry, '%s' is not the connect password... you can't "
"play this character at this point in time.", argument);
write_to_buffer( d, LOGIN_PROMPT, 0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
free_char( ch );
d->character = NULL;
d->connected_state = CON_GET_NAME;
}
/**************************************************************************/
void nanny_get_new_password(connection_data *d, const char *argument)
{
char_data *ch=d->character;
write_to_buffer( d, "\r\n", 2 );
if(str_len(argument) < 5 )
{
write_to_buffer( d,
"`cPassword must be at least five characters long.\r\nPassword: ",
0 );
return;
}
char *p;
char *pwdnew = dot_crypt( argument, CH(d)->name );
for( p = pwdnew; *p != '\0'; p++ )
{
if(*p == '~' )
{
write_to_buffer( d,"`cNew password not acceptable, try again.\r\nPassword: ",0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
return;
}
}
free_string( ch->pcdata->pwd );
ch->pcdata->pwd = str_dup( pwdnew );
write_to_buffer( d, "`cPlease retype password: ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
d->connected_state = CON_CONFIRM_NEW_PASSWORD;
}
/**************************************************************************/
void nanny_confirm_new_password(connection_data *d, const char *argument)
{
char_data *ch=d->character;
#if defined(unix)
write_to_buffer( d, "\r\n", 2 );
#endif
if(strcmp( dot_crypt( argument, ch->pcdata->pwd ), ch->pcdata->pwd ) )
{
write_to_buffer( d, "Passwords don't match.\r\nEnter a new password: ",0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
d->connected_state = CON_GET_NEW_PASSWORD;
return;
}
if(!IS_IRCCON(d)){
write_to_buffer( d, echo_on_str, 0 );
write_to_buffer( d, "`cDo you want to play with ansi colour?\r\n", 0 );
write_to_buffer( d, "`c(you can toggle at anytime once within the game by typing colour)\r\n", 0 );
d->connected_state = CON_GET_COLOUR;
}else{ // automatically turn on colour for IRC connections - default them to irc white
d->colour_mode=CT_IRCWHITE;
ch->pcdata->colourmode=CT_IRCWHITE;
nannysup_email_check(d,argument);
}
}
/**************************************************************************/
void nanny_get_colour(connection_data *d, const char *argument)
{
char_data *ch=d->character;
switch( *argument )
{
default:
write_to_buffer(d,"Please type Yes or No ",0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
return;
break;
case 'y' : case 'Y':
ch->pcdata->colourmode=CT_ANSI;
ch->println("`?C`?o`?l`?o`?u`?r`? `?i`?s `?n`?o`?w `?O`?N`?!`c");
break;
case 'n' : case 'N':
d->colour_mode=CT_NOCOLOUR;
ch->pcdata->colourmode=CT_NOCOLOUR;
write_to_buffer(d,"You now have colour disabled.\r\n",0);
break;
}
nannysup_email_check(d,argument);
}
/**************************************************************************/
void nanny_get_new_race(connection_data *d, char *argument)
{
char arg[MIL];
char_data *ch=d->character;
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);
}
write_to_buffer(d, "What city do you want to come from?`1",0);
return;
}
if(!GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_CREATION) && !strcmp(arg,"raceinfo"))
{
CH(d)->wrapln("`cSee \"help `=_attributes`c\" and "
"\"help `=_'creation points'`c\" for an explaination of "
"what the following numbers relate to.");
do_raceinfo(ch, "");
ch->print("`cEnter the name of the city you would like to come from: `c");
if(IS_IRCCON(d)){
ch->print_blank_lines(1);
}
return;
}
int race = race_lookup(argument);
if(race == -1 || !race_table[race]->creation_selectable()
|| (race_table[race]->remort_number > d->creation_remort_number))
{
if(IS_NULLSTR(argument)){
CH(d)->printf("You have to type something!`1");
}else{
CH(d)->printf("'%s' is not a valid city.`1", argument);
}
if(!codehelp(CH(d), "racial_option", false)){
CH(d)->printf("Please select your city from one of the following:`1 ");
int count=0;
for( race = 0; race_table[race]; race++ )
{
// creation selectable pc races only
if(!race_table[race]->creation_selectable()
|| (race_table[race]->remort_number > d->creation_remort_number)){
continue;
}
CH(d)->printf(" `S[`Y%12.12s`S]", race_table[race]->name);
if(++count%5==0){
CH(d)->printf("`c\r\n ");
}
}
CH(d)->printf("`1`cType in the name of the city you wish to come from:`1");
}
return;
}
CH(d)->printf("Race '%s' selected.`1`1", race_table[race]->name);
ch->race = race;
ch->affected_by = ch->affected_by|race_table[race]->aff;
REMOVE_BIT(ch->affected_by, AFF_FLYING); // new players dont start off flying
affect_fly_update(ch); // set/remove DYN_MAGICAL_FLYING as required
ch->affected_by2= ch->affected_by2|race_table[race]->aff2;
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 racial skills
for(int i = 0; i < MAX_RACIAL_SKILLS; i++){
if(race_table[race]->skills[i]==-1){
break;
}
group_add(ch,skill_table[race_table[race]->skills[i]].name,false, 1); // all racial skills are 1%
}
// add cost
ch->pcdata->points = race_table[race]->points;
ch->size = race_table[race]->size;
write_to_buffer( d, "`cWhat gender is your character (M/F)? ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
d->connected_state = CON_GET_NEW_SEX;
}
/**************************************************************************/
void nanny_get_new_sex(connection_data *d, const char *argument)
{
char_data *ch=d->character;
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.\r\nWhat IS your sex? ", 0 );
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
return;
}
if(GAMESETTING5(GAMESET5_CREATION_ASK_IF_WANT_AUTOMAP_ON)){
ch->lines += 15;
if(!codehelp(CH(d), "automap_option", CODEHELP_ALL_BUT_PLAYERS)){
ch->printf("Do you want the automap option enabled?\r\n");
}
ch->lines -= 15;
d->connected_state=CON_GET_AUTOMAP;
}else{
// automap defaults to on automatically,
// unless game is configured to ask in the gamesettings
SET_BIT(d->character->act,PLR_AUTOMAP);
// start class selection
connected_to_CON_REROLL_STATS(d);
}
}
/**************************************************************************/
void nanny_get_new_class(connection_data *c, char *argument)
{
char arg[MIL];
char tempbuf[MIL];
char_data *ch=c->character;
one_argument(argument,arg);
if(!strcmp(arg,"help")){
argument = one_argument(argument,arg);
if(IS_NULLSTR(argument)){
do_help(ch,"classes");
}else{
do_help(ch,argument);
}
ch->println("What class do you wish to be? ");
return;
}
if(!GAMESETTING5(GAMESET5_CLASSINFO_DISABLED_IN_CREATION) && !strcmp(arg,"classinfo"))
{
argument = one_argument(argument,arg);
ch->print_blank_lines(1);
ch->wrapln("`cSee \"help `=_basexp`c\", \"help `=_prime`c\" and "
"\"help `=_attributes`c\" for an explaination of "
"what the following values relate to.");
if(!GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_CREATION)){
ch->println("`=Craceinfo`c is also available at this stage in creation for reference purposes.");
}
if(IS_NULLSTR(argument)){
do_classinfo(ch, race_table[ch->race]->name);
if(GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_CREATION)){
ch->wrapln("You can also look at the base xp amounts for other cities "
"(for comparision purposes), by typing 'RCLASSINFO <CITYNAME>`c'.");
}else{
ch->wrapln("You can also look at the base xp amounts for other races "
"(for comparision purposes), by typing 'classinfo <racename>'... "
"use 'raceinfo' to get a list of races.");
}
}else{
do_classinfo(ch, argument);
}
ch->print("`cEnter the name of the class would you like to play: `c");
ch->print_blank_lines(IS_IRC(ch)?1:0);
return;
}
if(!GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_CREATION) && !strcmp(arg,"raceinfo"))
{
ch->wrapln("`cSee \"help `=_attributes`c\" and "
"\"help `=_'creation points'`c\" for an explaination of "
"what the following values relate to.");
do_raceinfo(ch, "");
ch->print("`cEnter the name of the CLASS would you like to play: `c");
ch->print_blank_lines(IS_IRC(ch)?1:0);
return;
}
int iClass= class_lookup(argument);
if(iClass == -1
|| !class_table[iClass].creation_selectable
|| (class_table[iClass].remort_number > c->creation_remort_number))
{
ch->printlnf("'%s' is not a recognised class.", argument);
ch->print("What is your class? ");
ch->print_blank_lines(IS_IRC(ch)?1:0);
return;
}
if(race_table[ch->race]->class_exp[iClass]<1000){
ch->printlnf("The %s class is not available for your city sorry.",
class_table[iClass].name);
ch->print("What IS your class? ");
ch->print_blank_lines(IS_IRC(ch)?1:0);
return;
}
ch->clss = iClass;
ch->pcdata->perm_hit=race_table[ch->race]->start_hp;
ch->max_hit=ch->pcdata->perm_hit;
ch->hit=ch->max_hit;
int langsn=race_table[ch->race]->language->gsn;
if(langsn>0){
ch->pcdata->learned[langsn]=100;
}
ch->language=race_table[ch->race]->language;
// set players default short description
if(ch->short_descr[0]=='\0')
{
sprintf(tempbuf,"a %s %s",
(ch->sex==0 ? "sexless" : ch->sex==1 ? "male" : "female"),
race_table[ch->race]->name);
ch->short_descr= str_dup(tempbuf);
}
// turn on players auto defaults
SET_BIT(ch->act,PLR_AUTOREFORMAT);
SET_BIT(ch->act,PLR_AUTOLOOT);
SET_BIT(ch->act,PLR_AUTOASSIST);
SET_BIT(ch->act,PLR_AUTOGOLD);
SET_BIT(ch->act,PLR_AUTOEXIT);
SET_BIT(ch->act,PLR_AUTOSPLIT);
SET_BIT(ch->comm,COMM_SHOW_AFFECTS);
SET_CONFIG(ch, CONFIG_AUTOLANDONREST);
if(!GAMESETTING5(GAMESET5_AUTODAMAGE_DEFAULTS_OFF)){
SET_CONFIG2(ch,CONFIG2_AUTODAMAGE);
}
// log them if we autolog all new players
if(GAMESETTING4(GAMESET4_AUTOLOG_ALL_NEW_PLAYERS)){
SET_BIT(ch->act,PLR_LOG);
append_playerlog( ch, "Player log turned ON by GAMESET4_AUTOLOG_ALL_NEW_PLAYERS.");
}
ch->println("Applying primary stats for your class to your character..." );
nannysup_setprime_stats(ch);
if(IS_IRC(ch)){
sprintf(log_buf,"%s@%s new IRC player!!! (socket = %d)",
ch->name, c->remote_hostname, c->connected_socket);
}else{
sprintf(log_buf,"%s@%s new player!!! (socket = %d)",
ch->name, c->remote_hostname, c->connected_socket);
}
log_string(log_buf);
wiznet("Newbie alert! Welcome $N.",ch,NULL,WIZ_NEWBIE,0,0);
wiznet(log_buf,NULL,NULL,WIZ_SITES,0,get_trust(ch));
// alert newbie support of an incoming newbie
nsupport_newbie_alert( ch, false );
connected_to_CON_GET_ALLIANCE(c);
}
/**************************************************************************/
void nanny_reroll_stats(connection_data *d, char *argument)
{
char_data *ch=d->character;
char arg[MIL];
one_argument(argument,arg);
switch( *arg)
{
case 'n' : case 'N':
// dont let people reroll more than 100 times
if(ch->pcdata->reroll_counter>20)
{
d->write("\r\n"
"\r\n`cFind something better to do with your time!\r\n\r\n",0);
logf("%s %s (%d) dropped due to rerolling over 20 times.",
CH(d)->name, d->remote_hostname, d->connected_socket );
connection_close(d);
return;
}
// reroll and show the stats
write_to_buffer(d,"Rerolling please wait.\r\n",0);
roll_stats(d);
if(!ch->pcdata->reroll_counter)
{
write_to_buffer(d,"`cNote: Attributes are rolled with a bias in favour doing less rerolls.\r\n",0);
write_to_buffer(d,"`cThe attributes rolling system has been changed since dawn1.1 and will NOT give\r\n"
"`chigh attributes like it used to, also note that modifiers now start at 60 not 70!\r\n",0);
}
ch->pcdata->reroll_counter++;
break;
// player keeps stats
case 'y' : case 'Y':
connected_to_CON_GET_NEW_CLASS(d);
break;
default:
{
if(!strcmp(arg,"help"))
{
argument = one_argument(argument,arg);
if(IS_NULLSTR(arg)){
do_help(ch,"attributes");
}else{
do_help(ch,argument);
}
ch->println("`cAre you happy with the attributes above the help entry? (Y, N): ");
return;
}
write_to_buffer(d,"`cPlease type Y, N or HELP? ",0);
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
}
break;
}
}
/**************************************************************************/
void nanny_get_alliance(connection_data *d, const char *argument)
{
char_data *ch=d->character;
if(is_number(argument))
{
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
if(atoi(argument)<-2 || atoi(argument)>2)
{
write_to_buffer(d,"`cValue between -2 and 2 please:",0);
return;
}
}else{
if(atoi(argument)<-3 || atoi(argument)>3)
{
write_to_buffer(d,"`cValue between -3 and 3 please:",0);
return;
}
}
ch->alliance=atoi(argument);
{
write_to_buffer(d,
"`cThe second half of you alignment is your TENDENCY towards law and chaos,\r\n",0);
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
write_to_buffer(d,
"`cthis value can be from -2 to 2(including 0 being neutral) 2 being lawful,\r\n"
"`clawful and -2 being chaotic. \r\nWhat is your choice? ",0);
}else{
write_to_buffer(d,
"`cthis value can be from -3 to 3(including 0 being neutral) 3 being extremely,\r\n"
"`clawful and -3 being extremely chaotic. \r\nWhat is your choice? ",0);
}
if(IS_IRCCON(d)){
write_to_buffer( d, "\r\n", 0 );
}
d->connected_state = CON_GET_TENDENCY;
}
}else{
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
write_to_buffer(d,"`cThat is not a number, try again(-2 through 2):",0);
}else{
write_to_buffer(d,"`cThat is not a number, try again(-3 through 3):",0);
}
return;
}
}
/**************************************************************************/
void nanny_get_tendency(connection_data *d, const char *argument)
{
char_data *ch=d->character;
if(is_number(argument))
{
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
if(atoi(argument)<-2 || atoi(argument)>2)
{
write_to_buffer(d,"Value between -2 and 2 please:",0);
return;
}
}else{
if(atoi(argument)<-3 || atoi(argument)>3)
{
write_to_buffer(d,"Value between -3 and 3 please:",0);
return;
}
}
{
ch->tendency=atoi(argument);
if(d->ident_confirmed){
CH(d)->host_validated=1;
}
if(ch->version<6)
{
ch->version=6;
write_to_buffer(d,"\r\n",0);
// loop thru all the groups giving new character all the ones
// his/her class can get for free and the free for all's
for ( int lgn = 0; !IS_NULLSTR(skillgroup_table[lgn].name); lgn++ )
{
if( skillgroup_table[lgn].rating[ch->clss]==0
|| IS_SET(skillgroup_table[lgn].flags, SKILLGROUP_FREE_FOR_ALL))
{
gn_add(ch, lgn);
}
}
// give them some defaults
ch->pcdata->learned[gsn_recall] = 50;
/* if(GAMESETTING5(GAMESET5_CREATION_DISABLE_CUSTOMIZATION)
|| HAS_CLASSFLAG(ch, CLASSFLAG_NO_CUSTOMIZATION)
|| IS_SET(race_table[ch->race]->flags, RACEFLAG_NO_CUSTOMIZATION))
{
*/
nanny_new_player_not_customizing(d);
return;
// }
/*
CH(d)->printf("`cCustomization");
write_to_buffer(d,"Do you wish to customize this character?\r\n",0);
write_to_buffer(d,
"Customization takes time, but allows a wider range of skills and abilities.\r\n",0);
write_to_buffer(d,"(we recommend choosing no, unless you have played here before as\r\n",0);
write_to_buffer(d,"you can always gain skills at a later stage.)\r\n",0);
write_to_buffer(d,"Customize (Y/N)? ",0);
d->connected_state = CON_DEFAULT_CHOICE;
return;
*/
}
else
{
if(IS_IMMORTAL(ch) )
{
do_help( ch, "imotd" );
ch->hit_return_to_continue();
d->connected_state = CON_READ_IMOTD;
}
else
{
if(IS_IRCCON(d)){
do_help( ch, "irc-motd" );
}else{
do_help( ch, "motd" );
}
ch->hit_return_to_continue();
d->connected_state = CON_READ_MOTD;
}
}
}
}
else
{
if(GAMESETTING(GAMESET_MAX_ALIGN_RANGE22)){
write_to_buffer(d,"That is not a number, try again(-2 through 2):",0);
}else{
write_to_buffer(d,"That is not a number, try again(-3 through 3):",0);
}
return;
}
}
/**************************************************************************/
void nanny_default_choice(connection_data *d, const char *argument)
{
char_data *ch=d->character;
write_to_buffer(d,"\r\n",2);
switch( argument[0] )
{
case 'y': case 'Y':
{
int langsn=race_table[ch->race]->language->gsn;
if(langsn>0){
ch->pcdata->learned[langsn]=100;
}
ch->language=race_table[ch->race]->language;
ch->gen_data = new_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:\r\n",0);
do_skills(ch,"");
do_help(ch,"menu-choice");
d->connected_state = CON_GEN_GROUPS;
}
break;
case 'n': case 'N':
{
nanny_new_player_not_customizing(d); // take some defaults, then d->connected_state -> CON_READ_MOTD
}
break;
default:
write_to_buffer( d, "Please answer (Y/N)? ", 0 );
return;
}
}
/**************************************************************************/
void nanny_gen_groups(connection_data *d, char *argument)
{
char_data *ch=d->character;
ch->println("");
if(!str_cmp(argument,"done") || !str_cmp(argument,"doneconfirm"))
{
if(ch->pcdata->points == race_table[ch->race]->points)
{
ch->println("You didn't pick anything.\r\n");
return;
}
if(str_cmp(argument,"doneconfirm")){
if(ch->pcdata->points < 40)
{
ch->wrapln("You haven't take at least 40 points of skills and groups... "
"You can add more skills without affecting the amount of experience required to level. "
"If you wish to continue without adding anymore skills/groups, type `=Cdoneconfirm`c");
return;
}
}
ch->printf("Creation points: %d\r\n",ch->pcdata->points);
ch->printf("Experience per level: %d\r\n",
exp_per_level(ch,ch->pcdata->points));
if(ch->pcdata->points < 40)
ch->train = (40 - ch->pcdata->points + 1) / 2;
free_gen_data(ch->gen_data);
ch->gen_data = NULL;
write_to_buffer( d, "\r\n", 2 );
if(IS_IRCCON(d)){
do_help( ch, "irc-motd" );
}else{
do_help( ch, "motd" );
}
ch->hit_return_to_continue();
d->connected_state = CON_READ_MOTD;
return;
}
if(!parse_gen_groups(ch,argument)){
ch->println("That isn't a valid selection, (type help if you are stuck):\r\n");
}
ch->println("\r\n");
do_help(ch,"menu-choice");
}
/**************************************************************************/
void do_mobloglist( char_data *ch, char *argument);
/**************************************************************************/
void nanny_read_imotd(connection_data *d, const char *)
{
char_data *ch=d->character;
write_to_buffer(d,"\r\n",2);
if(IS_IRCCON(d)){
do_help( ch, "irc-motd" );
}else{
do_help( ch, "motd" );
}
ch->hit_return_to_continue();
if(IS_ADMIN(ch)){
// check the resolver version
if(resolver_running && resolver_version<1400){
ch->titlebar("UPDATE THE DNS RESOLVER");
ch->wrapln("The dns resolver program (resolver) is an old version and "
"needs to be updated. On a linux/bsd/unix platform this can be done by "
"deleting the existing resolver program and recompile the code. "
"On the Win32 platform you can "
"download the latest version of the resolver.exe file from"
" `1http://www.dawnoftime.org.`1This message is only displayed to the admin.");
ch->titlebar("");
}
// tell them about the moblogs on
do_mobloglist(ch, "auto");
}
d->connected_state = CON_READ_MOTD;
}
/**************************************************************************/
void visual_debug_flush( connection_data *d);
/**************************************************************************/
// Deal with sockets that haven't logged in yet.
void nanny( connection_data *d, char *argument )
{
// logf("Nanny: d->connected_state %d, '%s' %d %d .", d->connected_state,
// argument, *argument, *(argument+1) ); // debug testing code
if(d->connected_state!= CON_FTP_DATA && d->connected_state!= CON_DETECT_CLIENT_SETTINGS){
while( is_space(*argument) ){
argument++;
}
logf("Start nanny state %2d (sock=%d)", d->connected_state, d->connected_socket);
}
if(d->visual_debugging_enabled && d->visual_debug_flush_before_prompt){
visual_debug_flush( d );
}
switch( d->connected_state )
{
default:
bugf("Nanny: bad d->connected_state %d (sock=%d).", d->connected_state, d->connected_socket);
connection_close( d );
break;
// a new connection begins in state CON_DETECT_CLIENT_SETTINGS
case CON_DETECT_CLIENT_SETTINGS: nanny_detect_client_settings(d, argument); break;
case CON_GET_NAME: nanny_get_name(d, argument); break;
case CON_CONFIRM_CREATING_NEW: nanny_confirm_creating_new(d, argument); break;
case CON_GET_CONNECT_PASS2CREATE: nanny_get_connect_password_before_creating(d, argument); break;
case CON_GET_CREATION_PASSWORD: nanny_get_creation_password(d, argument); break;
case CON_GET_CONNECT_PASSWORD: nanny_get_connect_password(d, argument); break;
case CON_NAME_SELECT: nanny_name_select(d, argument); break;
case CON_CONFIRM_NEW_NAME: nanny_confirm_new_name(d, argument); break;
case CON_RESOLVE_IP: nanny_resolve_ip(d, argument); break;
case CON_GET_EMAIL: nanny_get_email(d, argument); break;
case CON_RECHECK_EMAIL: nanny_recheck_email(d, argument); break;
case CON_ENTER_UNLOCK_ID: nanny_enter_unlock_id(d, argument); break;
case CON_GET_AUTOMAP: nanny_get_automap(d, argument); break;
case CON_GET_OLD_PASSWORD: nanny_get_old_password(d, argument); break;
case CON_BREAK_CONNECT: nanny_break_connect(d, argument); break;
case CON_GET_NEW_PASSWORD: nanny_get_new_password(d, argument); break;
case CON_CONFIRM_NEW_PASSWORD: nanny_confirm_new_password(d, argument); break;
case CON_GET_COLOUR: nanny_get_colour(d, argument); break;
case CON_GET_NEW_RACE: nanny_get_new_race(d, argument); break;
case CON_GET_NEW_SEX: nanny_get_new_sex(d, argument); break;
case CON_GET_NEW_CLASS: nanny_get_new_class(d, argument); break;
case CON_REROLL_STATS: nanny_reroll_stats(d, argument); break;
case CON_GET_ALLIANCE: nanny_get_alliance(d, argument); break;
case CON_GET_TENDENCY: nanny_get_tendency(d, argument); break;
case CON_DEFAULT_CHOICE: nanny_default_choice(d, argument); break;
case CON_GEN_GROUPS: nanny_gen_groups(d, argument); break;
case CON_READ_IMOTD: nanny_read_imotd(d, argument); break;
case CON_READ_MOTD: nanny_read_motd(d, argument ); break;
case CON_FTP_AUTH: handle_ftp_auth(d,argument); break;
case CON_FTP_COMMAND: handle_ftp_command(d,argument); break;
case CON_FTP_DATA: handle_ftp_data(d,argument); break;
}
}
/**************************************************************************/
// Parse a name for acceptability.
bool check_parse_name( char *name )
{
// Reserved words.
if(is_name( name, "auto someone something the you new self system dawnftp mudftp" ))
return false;
// some potentially offensive/inappropriate names in hex :)
if(is_name_infix( name,
"\x66\x75\x63\x6b \x70\x68\x75\x63\x6b \x66\x75\x6b \x70\x68\x75\x6b "
"\x73\x68\x69\x74 \x64\x61\x6d\x6e \x63\x6f\x63\x6b \x63\x75\x6e\x74 "
"\x62\x6c\x6f\x77\x6a\x6f\x62 \x61\x73\x73\x68\x6f\x6c\x65 "
"\x70\x75\x73\x73\x79 \x6a\x65\x73\x75\x73 \x67\x6f\x64 "
"\x61\x6e\x67\x65\x6c \x73\x61\x74\x61\x6e "
"\x6c\x75\x63\x69\x66\x69\x65\x72 \x64\x65\x6d\x6f\x6e "
"\x6f\x73\x61\x6d\x61 \x73\x61\x64\x61\x61\x6d"))
{
return false;
}
// just plain unoriginal/possibly intending to offend
if(is_name( name,
"merlin gandolf gandalf hero takhisis paladine majere morgion glarth "
"trispringer chemosh zivilyn alexander belrak death angel bozo stupid "
"beavis butthead mohammed mohammad buffy willow zander doom slayer rules rulez "
"bauhaus lunitari solinari nuitari devil yugi anime penis assmunch "
"kiri-jolith mishakal habbakuk branchala gilean sirrion reorx "
"chislev shinare sargonnas zeboim hiddukel trinity morpheus "
"blitz blytz budda buddah garlo blah blood buto cypher neo sliver "
"alaric deity genocide freedalis gremlic hack hate king knight "
"baron lord count prince princess darth vader lestat night zero "
"victor viktor vashiva dashiva tinkle tanis sanctus rhuid rude"))
return false;
// reference names
if(is_name( "none", name)) // none - used by olc
return false;
if(is_name( "self", name)) // self - used to reference self
return false;
if(is_name( "all", name)) // everyone in the game
return false;
if(is_name( "system", name))
return false;
// council related names
if(is_exact_name( "council", name ))
return false;
// next loop thru all the council names as defined in council_flags[]
// admin can read all those notes
{
int index;
for(index = 0; !IS_NULLSTR(council_flags[index].name); index++)
{
if(is_exact_name( council_flags[index].name, name )){
return false;
}
}
}
// next few are for allowing notes to certain groups
if(is_name( "imm", name)) // immortals
return false;
if(is_name( "hero", name)) // heros
return false;
if(is_name( "heros", name)) // heros
return false;
if(is_name( "nsupport", name)) // newbie support
return false;
if(is_name( "head", name)) // head of departments
return false;
if(is_name( "noble", name)) // nobles
return false;
if(is_name( "admin", name)) // administrators
return false;
if(is_name( "imp", name)) // implementors
return false;
if(is_name( "rpsupport", name)) // role playing support
return false;
if(is_name( "olc", name)) // olc note group security >4
return false;
if(is_name( "build", name)) // olc note group security >0
return false;
if(is_name( "nsupport", name)) // newbie support
return false;
if(is_name( "bard", name )) // bards, for notes to bard
return false;
if(is_name( "karn", name)) // karns
return false;
// can't be named after clans
if(clan_nlookup(name)>0)
return false;
// can't be named after a race
if(race_exact_lookup(name)>=0){
return false;
}
// can't be named after a class
if(class_exact_lookup(name)>=0){
return false;
}
// Length restrictions.
if(str_len(name) <= 2 )
return false;
if(str_len(name)>12)
return false;
if(name_confirmed)
return true;
// player specific
if(is_name( "kal", name)) // kalahn
return false;
if(is_name_infix( name, "alahn elahn alehn elehn nhala")) // kalahn
return false;
if(is_name( "yle", name)) // ylerin
return false;
if(is_name( "quox", name)) // quoxatyl
return false;
if(is_name( "reav", name)) // reave
return false;
if(is_name( "imi", name)) // imidazole
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(!is_alpha(*pc) && *pc!='-')
return false;
if(is_upper(*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 > (int) (str_len(name) / 2) && str_len(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;
}
}
}
{
// Prevent players from naming themselves after pkilled players
FILE* file;
char buf[MSL];
sprintf(buf, "%s%s", DEAD_DIR, name);
fclose(fpReserve); // close the reserve file
file = fopen (buf, "r"); // attempt to to open pkilled pfile
if(file)
{
fclose(file);
fpReserve = fopen( NULL_FILE, "r" );
return false;
}
fpReserve = fopen( NULL_FILE, "r" ); // reopen the reserve file
}
// Prevent players from naming themselves after deleted players
if(file_exists("%s%s", DELETE_DIR, pfile_filename(name))){
return false;
}
// Prevent players from naming themselves after dead players
if(file_exists("%s%s", DEAD_DIR, pfile_filename(name))){
return false;
}
return true;
}
/**************************************************************************/
// extremely ugly routine... needs a complete rewrite
// if someone can be bothered.
void roll_stats(connection_data *d)
{
char_data *ch, *v;
int i;
int total;
int bias;
char buf[MSL], sendbuf[MSL];
char * widthbuf=" ";
bias = 0;
sendbuf[0]='\0';
ch = d->character;
total=0;
v=ch;
// generate the stats
{
attributes_set rm_stats_set;
gen_rolemaster_stats(&rm_stats_set, ch->pcdata->reroll_counter);
for(i=0; i<MAX_STATS; i++)
{
ch->perm_stats[i]= rm_stats_set.perm[i];
ch->potential_stats[i]=rm_stats_set.potential[i];
}
}
ch->pcdata->reroll_counter++;
sprintf(buf," `cStrength (ST):`g%3d`c(`B%3d`c) Constitution (CO):`g%3d`c(`B%3d`c)\r\n",
v->perm_stats[STAT_ST], v->potential_stats[STAT_ST],
v->perm_stats[STAT_CO], v->potential_stats[STAT_CO]);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
sprintf(buf," `cQuickness(QU):`g%3d`c(`B%3d`c) Agility (AG):`g%3d`c(`B%3d`c)\r\n",
v->perm_stats[STAT_QU], v->potential_stats[STAT_QU],
v->perm_stats[STAT_AG], v->potential_stats[STAT_AG]);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
sprintf(buf," `cPresence (PR):`g%3d`c(`B%3d`c) Self-Discipline(SD):`g%3d`c(`B%3d`c)\r\n",
v->perm_stats[STAT_PR], v->potential_stats[STAT_PR],
v->perm_stats[STAT_SD], v->potential_stats[STAT_SD]);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
sprintf(buf," `cEmpathy (EM):`g%3d`c(`B%3d`c) Memory (ME):`g%3d`c(`B%3d`c)\r\n",
v->perm_stats[STAT_EM], v->potential_stats[STAT_EM],
v->perm_stats[STAT_ME], v->potential_stats[STAT_ME]);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
sprintf(buf," `cIntuition(IN):`g%3d`c(`B%3d`c) Reasoning (RE):`g%3d`c(`B%3d`c)\r\n",
v->perm_stats[STAT_IN], v->potential_stats[STAT_IN],
v->perm_stats[STAT_RE], v->potential_stats[STAT_RE]);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
sprintf(buf," `ggreen is starting value, `B(blue) is potential with training`c.\r\n");
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
if(GAMESETTING(GAMESET_SHOW_STAT_AVERAGES_IN_CREATION)){
int avpot=0, avperm=0;
for(i=0; i<MAX_STATS; i++)
{
avperm+= ch->perm_stats[i];
avpot+= ch->potential_stats[i];
}
sprintf(buf," `gaverage start %3d`B (average potential %3d)`c\r\n", avperm/MAX_STATS, avpot/MAX_STATS);
strcat(sendbuf, widthbuf);
strcat(sendbuf, buf);
}
strcat(sendbuf, "Are you happy with these attributes?\r\n");
ch->printf("`cAttributes Selection");
ch->print(sendbuf);
}
/**************************************************************************/
// returns true if the person was disconnected
int count_creation_connections_per_hour(connection_data *d){
CREATION_COUNTER_DATA* tc;
int count=0;
// check them to the head of the linked list
for(tc = creation_counter; tc; tc=tc->next)
{
if( !str_cmp(tc->ip, d->remote_ip)
&& (tc->time> current_time-60*60))
{
count++;
}
}
if(!GAMESETTING5(GAMESET5_RESTRICTED_CREATIONS_PER_HOUR) && count<40){
return 0;
}
return count;
}
/**************************************************************************/
// returns true if the person was disconnected
bool check_connection(connection_data *d){
if(GAMESETTING5(GAMESET5_DEDICATED_PKILL_STYLE_MUD)){
return false;
}
if(count_creation_connections_per_hour(d)>5){
d->write(note_format_string(str_dup(
"`1`1Due to abuse or potential abuse of the character creation system, "
"we limit the number of characters that can be created within "
"an hour or so from a single site. Try creating again an hour or so.`1`1")), 0);
logf("%s %s (%d) dropped - creating too many times.",
CH(d)->name, d->remote_hostname, d->connected_socket );
{
char log_buf[MSL];
sprintf( log_buf, "%s %s (%d) dropped - creating to many times.\r\n",
CH(d)->name, d->remote_hostname, d->connected_socket );
wiznet(log_buf,NULL,NULL,WIZ_SECURE,0,get_trust(CH(d)) );
}
connection_close(d);
return true;
}
return false;
}
/**************************************************************************/
void add_connection(connection_data *d)
{
CREATION_COUNTER_DATA* tc;
tc = new CREATION_COUNTER_DATA;
tc->ip = str_dup(d->remote_ip);
tc->time = current_time;
// add them to the head of the linked list
tc->next=creation_counter;
creation_counter=tc;
}
/**************************************************************************/
// go on to selecting the race
void nannysup_past_email_check(connection_data *d, const char *)
{
int race;
// display races
CH(d)->wrapln(
"It it now time to select a city... You can read online help on any "
"city by simply typing `RHELP <CITYNAME>`c where `R<CITYNAME>`c is the "
"name of the city you are interested in (e.g. `RHELP ATHENIAN`c). "
"If you are unsure about which city to play, we recommend Athenian as "
"they are good all round city, and start have the largest population.`1");
if(!GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_CREATION)){
CH(d)->wraplnf(
"Note: You can type `Rcityinfo`c for a list of cities, their "
"citizenship attribute modifiers, creation point cost and "
"maximum hitpoints.`1");
}
if(!codehelp(CH(d), "racial_option", false)){
CH(d)->printf("Please select your city from one of the following:`1 ");
int count=0;
for( race = 0; race_table[race]; race++ )
{
// creation selectable pc races only
if(!race_table[race]->creation_selectable()
|| (race_table[race]->remort_number > d->creation_remort_number)){
continue;
}
CH(d)->printf(" `S[`Y%12.12s`S]", race_table[race]->name);
if(++count%5==0){
CH(d)->printf("`c\r\n ");
}
}
CH(d)->printf("`1`cType in the name of the city you wish to play now:`1");
}
d->connected_state = CON_GET_NEW_RACE;
}
/**************************************************************************/
void nannysup_setprime_stats( char_data *ch )
{
bool changed = false;
// if character's prime stats are below 80 they get set to 80.
// if character's prime stats are 90 + they get +5 to their prime to a max of 101
int old;
// Do first primary stat
if(ch->potential_stats[class_table[ch->clss].attr_prime[0]] < 80 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[0]];
ch->potential_stats[class_table[ch->clss].attr_prime[0]] = 80;
ch->printlnf("Your %s has increased from %d to 80!",
stat_flags[class_table[ch->clss].attr_prime[0]].name,
old);
changed = true;
}
else if(ch->potential_stats[class_table[ch->clss].attr_prime[0]] < 90 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[0]];
ch->potential_stats[class_table[ch->clss].attr_prime[0]]
+= (UMIN(ch->potential_stats[class_table[ch->clss].attr_prime[0]]-78, 10)/2);
ch->printlnf("Your %s has increased from %d to %d!",
stat_flags[class_table[ch->clss].attr_prime[0]].name,
old,
ch->potential_stats[class_table[ch->clss].attr_prime[0]]);
changed = true;
}
else // if(ch->potential_stats[class_table[ch->clss].attr_prime[0]] => 90 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[0]];
ch->potential_stats[class_table[ch->clss].attr_prime[0]] += 5;
if(ch->potential_stats[class_table[ch->clss].attr_prime[0]] > 101)
{
ch->potential_stats[class_table[ch->clss].attr_prime[0]] = 101;
}
ch->printlnf("Your %s has increased from %d to %d!",
stat_flags[class_table[ch->clss].attr_prime[0]].name,
old,
ch->potential_stats[class_table[ch->clss].attr_prime[0]]);
changed = true;
}
// Do second primary stat
if(ch->potential_stats[class_table[ch->clss].attr_prime[1]] < 80 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[1]];
ch->potential_stats[class_table[ch->clss].attr_prime[1]] = 80;
ch->printlnf("Your %s has increased from %d to 80!",
stat_flags[class_table[ch->clss].attr_prime[1]].name,
old);
changed = true;
}
else if(ch->potential_stats[class_table[ch->clss].attr_prime[1]] < 90 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[1]];
ch->potential_stats[class_table[ch->clss].attr_prime[1]]
+= (UMIN(ch->potential_stats[class_table[ch->clss].attr_prime[1]]-78, 10)/2);
ch->printlnf("Your %s has increased from %d to %d!",
stat_flags[class_table[ch->clss].attr_prime[1]].name,
old,
ch->potential_stats[class_table[ch->clss].attr_prime[1]]);
changed = true;
}
else // if(ch->potential_stats[class_table[ch->clss].attr_prime[1]] => 90 )
{
old=ch->potential_stats[class_table[ch->clss].attr_prime[1]];
ch->potential_stats[class_table[ch->clss].attr_prime[1]] += 5;
if(ch->potential_stats[class_table[ch->clss].attr_prime[1]] > 101)
{
ch->potential_stats[class_table[ch->clss].attr_prime[1]] = 101;
}
ch->printlnf("Your %s has increased from %d to %d!",
stat_flags[class_table[ch->clss].attr_prime[1]].name,
old,
ch->potential_stats[class_table[ch->clss].attr_prime[1]]);
changed = true;
}
if(!changed){
ch->println("Your stats have remained the same.");
}
return;
}
/**************************************************************************/
void do_clear_createcount( char_data *ch, char *argument )
{
if(str_cmp("confirm", argument)) {
ch->println("Syntax: clear_createcount confirm");
ch->println("notes: It clears the counter of who created in the last hour.");
return;
}
ch->println("Creation counter cleared.");
creation_counter=NULL;
return;
}
/**************************************************************************/
void nsupport_newbie_alert( char_data *ch, bool created )
{
connection_data *d;
for( d = connection_list; d != NULL; d = d->next )
{
if( d->connected_state == CON_PLAYING
&& CH(d)
&& d->character != ch
&& IS_NEWBIE_SUPPORT( d->character ))
{
// an existing newbie logging on,
// if they have newbie channel off, then no warning is given
if(created && !HAS_CONFIG( ch, CONFIG_NONEWBIE ))
{
d->character->printlnf( "`sNewbie '%s' has just logged on.`c", ch->name );
}
if(!created )
{
d->character->printlnf( "`sNew player '%s' is creating, please make them feel welcome when they arrive.", ch->name );
}
}
}
}
/**************************************************************************/
void greet_new_connection(connection_data *d);
/**************************************************************************/
// give time for the telnet option negotiation to work
void nanny_detect_client_settings(connection_data *c, char *argument)
{
bool t=c->fcommand;
c->fcommand=true;
#ifdef SHOW_CLIENT_DETECTION
if(c->outtop==0){
write_to_buffer( c, ".", 1);
if(c->connected_state_pulse_counter%42==0){
write_to_buffer( c, "\r\n", 2);
}
}
#endif
#ifdef SHOW_CLIENT_DETECTION
if(!IS_NULLSTR(argument)){
write_to_buffer( c, "^", 1);
}
#endif
if(!IS_NULLSTR(argument) || ++c->connected_state_pulse_counter>PULSE_PER_SECOND*4){
#ifdef SHOW_CLIENT_DETECTION
{
// write_to_buffer( c,".. detection completed.\033\133\062\113\r\n", 0);
// the above esc code sequence was used to delete the detect line
write_to_buffer( c,".. detection completed.\r\n", 0);
}
#endif
c->fcommand=t;
greet_new_connection(c);
// jump straight into username input if detection was aborted
// for any keystroke other than enter
c->connected_state=CON_GET_NAME;
if(!IS_NULLSTR(argument)){
if(*argument!=' ' && *(argument+1)!='\0'){
nanny(c, argument);
}
}
return;
}
c->fcommand=t;
}
/**************************************************************************/
/**************************************************************************/
/**************************************************************************/