// File : /adm/daemons/newuserd.c
//
// This is the character creation module.
// This daemon is called from logind.c if a player enters and requests an
// unused name. It then sets up the new user as per the user's preferences.
// Begun by Buddha, sometime in September 1992.
//
// Mobydick added race, skills, and stats, 10-11-92.
// Extended by Buddha in December 1992 and January 1993
//
// Psyche@TMI-2 (93/01/27) added acceptance of first-letter input
// when choosing gender and race.
//
// Streamlined and option addition added by Watcher@TMI (2/23/93)
//
// Watcher@TMI (4/15/93) added AUTO_WIZHOOD option.
//
// Languages added by Megadeath@TMI-2
//
// Mail registration added by Karathan (8/12/93)
//
// 94-11-09 : Leto fixed languages to mapping instead of string *
// 95-04-30 : Blue made RACES a #define in <user2.h>. Will do
// genders sometime too.
#include <logs.h>
#include <uid.h>
#include <priv.h>
#include <mudlib.h>
#include <config.h>
#include <login.h>
#include <login_macros.h>
#include <language.h>
#include <daemons.h>
#include <user2.h>
// Who knows why races are defined in newuserd, but hey.
static void set_skills(object player);
static void set_stats(object player);
void create()
{
seteuid(ROOT_UID);
}
void create_new_user(object user, string pass)
{
object body;
if (geteuid(previous_object()) != ROOT_UID) return;
user->SET_BODY(USER_OB); // let's assume a standard login
body = new(USER_OB);
body->set("name", (string)user->NAME, MASTER_ONLY);
body->set ("cap_name", capitalize((string)user->NAME), MASTER_ONLY) ;
body->set("snoopable", 1, MASTER_ONLY);
user->SET_BODY_OB(body);
cat(NPLAYER_INTRO);
// If EMAIL_REGISTRATION is defined in /include/login.h then check to see if
// this is a registered name with a predefined password.
#ifdef EMAIL_REGISTRATION
if (pass && stringp(pass) && pass != "")
{ write("Please enter the password sent to you with your\n" +
"registration acceptance: ");
input_to("get_pass", 3, pass, user, 0);
return; }
#endif /* EMAIL_REGISTRATION */
write("Please enter a unique password for your character. Do not use\n"+
"the password you use on your computer account, and please do not use\n"+
"any word that appears in the dictionary.\n") ;
input_to("new_pass", 3, user, 0);
}
static void new_pass(string pass, object user, int count)
{
if (strlen(pass) < 5)
{ write("\nI'm sorry, your password must be at least 5 characters.\n");
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write("Please change your password: ");
input_to("new_pass", 3, user, count + 1);
return; }
write("\nPlease reenter your password to confirm: ");
input_to("new_pass2", 3, pass, user, count);
}
static void new_pass2(string pass2, string pass, object user, int count)
{
if (pass == pass2)
{ user->SET_PASS(crypt(pass2, 0));
write("\n\nYour gender can be male, female, neuter, or hermaphrodite." +
"\nPlease enter your gender: ");
input_to("new_gender", 2, user, (object)user->BODY_OB, 0);
return; }
write("\nSorry, the passwords have to match.\n");
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write("Please enter your character's password: ");
input_to("new_pass", 3, user, count + 1);
}
static void get_pass(string pass, string prev, object user, int count)
{
if (crypt(pass, prev) != prev)
{ write("Sorry, that password is incorrect.\n");
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write("Please reenter your password: ");
input_to("get_pass", 3, prev, user, count + 1);
return; }
user->SET_PASS(prev);
write("\n\nYour gender can be male, female, neuter, or hermaphrodite." +
"\nPlease enter your gender: ");
input_to("new_gender", 2, user, (object)user->BODY_OB, 0);
}
static void new_gender(string g, object user, object body, int count)
{
if (!g || member_array(g, ({"male", "female", "neuter", "hermaphrodite",
"m", "f", "n", "h" })) == -1)
{ write("\nYou can only be male, female, neuter, or hermaphrodite.\n");
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write("Please enter your gender: ");
input_to("new_gender", user, body, count + 1);
return; }
// Psyche@TMI-2 (93/27/01): translates one-letter input to
// corresponding full word
// I have NEVER seen this date convention before. Please
// never use it again. Blue. 950430, by the way.
switch(g)
{ case "m": g = "male";
break;
case "f": g = "female";
break;
case "n": g = "neuter";
break;
case "h": g = "hermaphrodite";
break; }
body->set("gender", g, READ_ONLY);
printf("\nYour race can be one of:\n %-=60s\n", implode(RACES, ", "));
// write ("\nYour race can be human, elf, dwarf, gnome, or orc.\n") ;
write ("Please enter your race: ") ;
input_to("new_race", user, body, 0);
return ;
}
static void new_race(string r, object user, object body, int count)
{
string *rs;
if (!r || sizeof(rs = regexp(RACES, "^"+r)) != 1) {
// if (!r || member_array(r, ({"elf", "dwarf", "gnome", "human", "orc",
// "e", "d", "g", "h", "o" })) == -1)
// { write("\nYou must choose human, elf, dwarf, gnome, or orc.\n");
printf("\nYour race can be one of:\n %-=60s\n", implode(RACES, ", "));
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write ("Please enter your race: ") ;
input_to("new_race", user, body, count + 1);
return; }
// switch(r)
// { case "h": r = "human";
// //break;
// case "e": r = "elf";
// //break;
// case "d": r = "dwarf";
// //break;
// case "g": r = "gnome";
// //break;
// case "o": r = "orc";
// //break; }
body->set("race",r);
write("\nPlease enter your email address (user@host): ");
input_to("new_email", user, body, 0);
}
static void new_email(string e, object user, object body, int count)
{
string id, host;
if (sscanf(e, "%s@%s", id, host) != 2 || id == "" || host == "")
{ write("Mail address must be in the form user@host\n");
if (count > 2)
{ write("\nYou have taken too many tries.\n");
user->remove_user();
return; }
write("Please reenter your email address: ");
input_to("new_email", user, body, count + 1);
return; }
if(e=="user@host") write("How original...ah well.\n");
user->SET_EMAIL(e);
write("Please enter your real name: ");
input_to("get_real_name", user, body);
}
static void get_real_name(string rn, object user, object body)
{
if (!rn || rn == "") rn = "???";
user->SET_RNAME(rn);
// Ok, that's all we need to know from them... let's get them connected.
// the stats could be rolled, etc, but that's not my job to code -- buddha
set_stats(body);
set_skills(body);
seteuid(geteuid(user));
export_uid(body);
seteuid(getuid());
user->connect();
cat(NPLAYER_NEWS);
// If NEW_USER is defined in /include/logs.h then log the creation time.
#ifdef NEW_USER
log_file(NEW_USER, capitalize((string)user->NAME) + " was created on " +
extract(ctime(time()), 4, 15) + " from " + query_ip_name() + ".\n");
#endif /* NEW_USER */
// If AUTO_WIZHOOD is defined in /include/config.h then any newly created
// users will automatically be granted wizard status, and given the PATH
// given by the define. This would be handy on places like TMI where
// wizard bits are freely given.
#ifdef AUTO_WIZHOOD
user->set("wizard", 1);
body->set("PATH", AUTO_WIZHOOD);
write("\t[You have been granted automatic wizard status]\n");
#endif /* AUTO_WIZHOOD */
body->setup();
user->save_data();
body->save_data();
// If EMAIL_REGISTRATION is defined in /include/login.h then check to see if
// this is a registered name that now can be removed from the file.
#ifdef EMAIL_REGISTRATION
(void)BANISH_D->remove_mailreg_name(user->NAME);
#endif /* EMAIL_REGISTRATION */
}
int clean_up()
{
destruct(this_object());
return 1;
}
static void set_stats(object player) {
int strength, intelligence, dexterity, constitution ;
int hp, sp, total ;
//string *languages ;
mapping languages; // Leto
mapping stat ;
//languages = ({ }) ;
languages = ([]); // Leto
stat = allocate_mapping(4);
total = 0 ;
while (total<50 || total > 70) {
strength = 9+random(7)+random(7) ;
intelligence = 9+random(7)+random(7) ;
dexterity = 9+random(7)+random(7) ;
constitution = 9+random(7)+random(7) ;
total = strength + intelligence + dexterity + constitution ;
}
switch (player->query("race")) {
case "human" : {
languages = ([ "human" : 100 ]) ;
break ;
}
case "elf" : {
intelligence = intelligence + 3 ;
constitution = constitution - 2 ;
dexterity = dexterity + 1 ;
strength = strength - 2 ;
languages = ([ "elvish" : 100 ]) ;
break ;
}
case "dwarf" : {
intelligence = intelligence - 1 ;
dexterity = dexterity - 2 ;
constitution = constitution + 2 ;
strength = strength + 1 ;
languages = ([ "dwarvish" : 100 ]) ;
break ;
}
case "gnome" : {
strength = strength - 3 ;
dexterity = dexterity + 3 ;
constitution = constitution - 1 ;
intelligence = intelligence + 1 ;
languages = ([ "gnomish" : 100 ]) ;
break ;
}
case "orc" : {
strength = strength + 3 ;
constitution = constitution + 1 ;
dexterity = dexterity - 1 ;
intelligence = intelligence - 3 ;
languages = ([ "orcish" : 100 ]) ;
}
}
stat["strength"] = strength ;
stat["intelligence"] = intelligence ;
stat["dexterity"] = dexterity ;
stat["constitution"] = constitution ;
player->set("stat", stat, LOCKED) ;
#ifdef LANGUAGES
languages += ([ "common" : 100 ]) ;
player->set("languages", languages);
#endif
hp = 25 + constitution + random(21) ;
sp = 45 + intelligence + random(21) ;
player->set("hit_points", hp) ;
player->set("max_hp", hp, MASTER_ONLY);
player->set("spell_points", sp) ;
player->set("max_sp", sp, LOCKED);
return ;
}
static void set_skills(object player) {
player->wipe_skills() ;
player->set_skill("Thrusting weapons",0,"strength") ;
player->set_skill("Cutting weapons",0,"strength") ;
player->set_skill("Blunt weapons",0,"strength") ;
player->set_skill("Parrying defense",0,"dexterity") ;
player->set_skill("Shield defense",0,"dexterity") ;
player->set_skill("Combat spells",0,"intelligence") ;
player->set_skill("Healing spells",0,"intelligence") ;
player->set_skill("Divinations spells",0,"intelligence") ;
player->set_skill("Wilderness",0,"dexterity") ;
player->set_skill("First aid",0,"dexterity") ;
player->set_skill("Theft",0,"dexterity") ;
player->set_skill("Stealth",0,"dexterity") ;
return ;
}