mirror of
https://github.com/tbamud/tbamud.git
synced 2026-04-02 10:27:19 +02:00
Accounts update 1
This commit is contained in:
parent
c3db46da13
commit
76513050cb
20 changed files with 626 additions and 147 deletions
35
README.md
35
README.md
|
|
@ -1,19 +1,19 @@
|
|||
***Files for Dark Sun MUD.***
|
||||
***Files for Miranthas MUD.***
|
||||
|
||||
Dark Sun MUD is a continuation of tbaMUD/CircleMUD, which is built on DIKU MUD.
|
||||
Miranthas MUD is a continuation of tbaMUD/CircleMUD, which is built on DIKU MUD.
|
||||
The code here is freeware to honor that tradition.
|
||||
|
||||
Due to the sensitive nature of topics found in this setting, all characters and
|
||||
players are 18+. The game world is based on the D&D campaign setting Dark Sun
|
||||
(as close as possible).
|
||||
players are 18+. The game world is derived from several inspirational sources,
|
||||
most notably the former Armageddon MUD.
|
||||
|
||||
Roleplay is highly encouraged, but not enforced.
|
||||
|
||||
Features in Dark Sun MUD Alpha release:
|
||||
Features in Miranthas MUD Alpha release:
|
||||
|
||||
* The city of Tyr is available for exploration
|
||||
* The city of Caleran is available for exploration
|
||||
* Experience points and levels are removed in favor of skill based progression
|
||||
* Initial skills/spells based partly on tbaMUD code and Dark Sun 5e conversion
|
||||
* Initial skills/spells based partly on tbaMUD code and 5e conversion (to be cleaned up in later release)
|
||||
* Expanded emoting system for roleplay
|
||||
* Permanent character death - aka. hardcore mode
|
||||
* A hybrid "5e-like" system where:
|
||||
|
|
@ -42,11 +42,13 @@ Features in Dark Sun MUD Alpha release:
|
|||
* NPC's can now be assigned a class like a PC and inherit the relevant skills
|
||||
* PC's now use a short description for identification instead of name
|
||||
* Backgrounds are now available for PC's and NPC's
|
||||
* Account system for tracking players/characters over long periods of time
|
||||
|
||||
Features to be implemented in the next few releases:
|
||||
|
||||
* Race selection based on Dark Sun
|
||||
* The Merchant Calendar and moon cycles
|
||||
* Race/species selection
|
||||
* Subclass selection
|
||||
* New calendar and moon cycles
|
||||
* Heat based on time of day increases/decreases, changing hunger/thirst levels
|
||||
* Sandstorms
|
||||
* Shaded rooms
|
||||
|
|
@ -55,16 +57,17 @@ Features to be implemented in the next few releases:
|
|||
* Basic crafting system
|
||||
* Continued skill and spell improvements
|
||||
* Apartment rentals for storing your loot
|
||||
* Account system for tracking players/characters over long periods of time
|
||||
* Quest system to increase or decrease notoriety
|
||||
* Additional zones/cities based on Dark Sun world map
|
||||
* Resources on the world map can be claimed by different city-states
|
||||
* Enhanced quest system
|
||||
* Dialogue trees with NPC's
|
||||
* Additional zones/cities based on Miranthas world map
|
||||
* Resources on the world map can be claimed by different city-states or independent factions
|
||||
* Claimed resources improve quality of armor/weapons/food/prices available
|
||||
|
||||
...and down the road:
|
||||
|
||||
* Change to SQL database on the backend
|
||||
* Python abstraction layer for modern scripting support
|
||||
* Replace ASCII files in favor of SQL database on the backend
|
||||
* Replace DG Scripts with a Python abstraction layer for modern scripting support
|
||||
* Replace Oasis OLC with more modern interface for easing builder duties
|
||||
* Discord server integration for ticketing and community
|
||||
* Full documentation for admins and easy to follow improvement guides
|
||||
* ...something else I haven't thought of
|
||||
* ...suggestions from anyone who uses this game
|
||||
|
|
|
|||
1
lib/acctfiles/A-E/00
Normal file
1
lib/acctfiles/A-E/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
1
lib/acctfiles/F-J/00
Normal file
1
lib/acctfiles/F-J/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
1
lib/acctfiles/K-O/00
Normal file
1
lib/acctfiles/K-O/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
1
lib/acctfiles/P-T/00
Normal file
1
lib/acctfiles/P-T/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
1
lib/acctfiles/U-Z/00
Normal file
1
lib/acctfiles/U-Z/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
1
lib/acctfiles/ZZZ/00
Normal file
1
lib/acctfiles/ZZZ/00
Normal file
|
|
@ -0,0 +1 @@
|
|||
This is a placeholder file so the directory will be created
|
||||
175
src/accounts.c
Normal file
175
src/accounts.c
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
#include "conf.h"
|
||||
#include "sysdep.h"
|
||||
|
||||
#include "structs.h"
|
||||
#include "utils.h"
|
||||
#include "db.h"
|
||||
#include "accounts.h"
|
||||
|
||||
static void set_account_name(struct account_data *account, const char *name)
|
||||
{
|
||||
char tmp[MAX_INPUT_LENGTH];
|
||||
|
||||
if (!account || !name || !*name)
|
||||
return;
|
||||
|
||||
strlcpy(tmp, name, sizeof(tmp));
|
||||
CAP(tmp);
|
||||
|
||||
if (account->name)
|
||||
free(account->name);
|
||||
account->name = strdup(tmp);
|
||||
}
|
||||
|
||||
struct account_data *account_create(const char *name)
|
||||
{
|
||||
struct account_data *account;
|
||||
|
||||
CREATE(account, struct account_data, 1);
|
||||
set_account_name(account, name);
|
||||
return account;
|
||||
}
|
||||
|
||||
struct account_data *account_load(const char *name)
|
||||
{
|
||||
struct account_data *account;
|
||||
FILE *fl;
|
||||
char filename[PATH_MAX];
|
||||
char line[MAX_INPUT_LENGTH + 1];
|
||||
char tag[6];
|
||||
|
||||
if (!name || !*name)
|
||||
return NULL;
|
||||
|
||||
if (!get_filename(filename, sizeof(filename), ACCT_FILE, name))
|
||||
return NULL;
|
||||
|
||||
fl = fopen(filename, "r");
|
||||
if (!fl)
|
||||
return NULL;
|
||||
|
||||
account = account_create(NULL);
|
||||
|
||||
while (get_line(fl, line)) {
|
||||
tag_argument(line, tag);
|
||||
|
||||
if (!strcmp(tag, "Name"))
|
||||
set_account_name(account, line);
|
||||
else if (!strcmp(tag, "Pass"))
|
||||
strlcpy(account->passwd, line, sizeof(account->passwd));
|
||||
else if (!strcmp(tag, "Mail")) {
|
||||
if (account->email)
|
||||
free(account->email);
|
||||
account->email = strdup(line);
|
||||
} else if (!strcmp(tag, "Char")) {
|
||||
if (account->pc_name)
|
||||
free(account->pc_name);
|
||||
account->pc_name = strdup(line);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fl);
|
||||
|
||||
if (!account->name)
|
||||
set_account_name(account, name);
|
||||
|
||||
return account;
|
||||
}
|
||||
|
||||
int account_save(const struct account_data *account)
|
||||
{
|
||||
FILE *fl;
|
||||
char filename[PATH_MAX];
|
||||
|
||||
if (!account || !account->name || !*account->name)
|
||||
return 0;
|
||||
|
||||
if (!get_filename(filename, sizeof(filename), ACCT_FILE, account->name))
|
||||
return 0;
|
||||
|
||||
if (!(fl = fopen(filename, "w"))) {
|
||||
log("SYSERR: Couldn't open account file %s for write.", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
fprintf(fl, "Name: %s\n", account->name);
|
||||
fprintf(fl, "Pass: %s\n", account->passwd);
|
||||
if (account->email && *account->email)
|
||||
fprintf(fl, "Mail: %s\n", account->email);
|
||||
if (account->pc_name && *account->pc_name)
|
||||
fprintf(fl, "Char: %s\n", account->pc_name);
|
||||
|
||||
fclose(fl);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void account_free(struct account_data *account)
|
||||
{
|
||||
if (!account)
|
||||
return;
|
||||
|
||||
if (account->name)
|
||||
free(account->name);
|
||||
if (account->email)
|
||||
free(account->email);
|
||||
if (account->pc_name)
|
||||
free(account->pc_name);
|
||||
|
||||
free(account);
|
||||
}
|
||||
|
||||
int account_has_alive_pc(const struct account_data *account)
|
||||
{
|
||||
int pfilepos;
|
||||
|
||||
if (!account || !account->pc_name || !*account->pc_name)
|
||||
return 0;
|
||||
|
||||
pfilepos = get_ptable_by_name(account->pc_name);
|
||||
if (pfilepos < 0)
|
||||
return 0;
|
||||
if (IS_SET(player_table[pfilepos].flags, PINDEX_DELETED))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void account_set_pc(struct account_data *account, const char *pc_name)
|
||||
{
|
||||
char tmp[MAX_INPUT_LENGTH];
|
||||
|
||||
if (!account)
|
||||
return;
|
||||
|
||||
if (account->pc_name)
|
||||
free(account->pc_name);
|
||||
account->pc_name = NULL;
|
||||
|
||||
if (pc_name && *pc_name) {
|
||||
strlcpy(tmp, pc_name, sizeof(tmp));
|
||||
CAP(tmp);
|
||||
account->pc_name = strdup(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
void account_clear_pc(struct account_data *account)
|
||||
{
|
||||
if (!account)
|
||||
return;
|
||||
|
||||
if (account->pc_name)
|
||||
free(account->pc_name);
|
||||
account->pc_name = NULL;
|
||||
}
|
||||
|
||||
void account_refresh_pc(struct account_data *account)
|
||||
{
|
||||
if (!account || !account->pc_name || !*account->pc_name)
|
||||
return;
|
||||
|
||||
if (account_has_alive_pc(account))
|
||||
return;
|
||||
|
||||
account_clear_pc(account);
|
||||
account_save(account);
|
||||
}
|
||||
15
src/accounts.h
Normal file
15
src/accounts.h
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
#ifndef _ACCOUNTS_H_
|
||||
#define _ACCOUNTS_H_
|
||||
|
||||
struct account_data;
|
||||
|
||||
struct account_data *account_load(const char *name);
|
||||
struct account_data *account_create(const char *name);
|
||||
int account_save(const struct account_data *account);
|
||||
void account_free(struct account_data *account);
|
||||
int account_has_alive_pc(const struct account_data *account);
|
||||
void account_set_pc(struct account_data *account, const char *pc_name);
|
||||
void account_clear_pc(struct account_data *account);
|
||||
void account_refresh_pc(struct account_data *account);
|
||||
|
||||
#endif
|
||||
10
src/comm.c
10
src/comm.c
|
|
@ -65,6 +65,7 @@
|
|||
#include "interpreter.h"
|
||||
#include "handler.h"
|
||||
#include "db.h"
|
||||
#include "accounts.h"
|
||||
#include "house.h"
|
||||
#include "oasis.h"
|
||||
#include "genolc.h"
|
||||
|
|
@ -1451,6 +1452,7 @@ static void init_descriptor (struct descriptor_data *newd, int desc)
|
|||
newd->has_prompt = 1; /* prompt is part of greetings */
|
||||
STATE(newd) = CONFIG_PROTOCOL_NEGOTIATION ? CON_GET_PROTOCOL : CON_GET_CONNECT;
|
||||
CREATE(newd->history, char *, HISTORY_SIZE);
|
||||
newd->account = NULL;
|
||||
if (++last_desc == 1000)
|
||||
last_desc = 1;
|
||||
newd->desc_num = last_desc;
|
||||
|
|
@ -2126,6 +2128,9 @@ void close_socket(struct descriptor_data *d)
|
|||
break;
|
||||
}
|
||||
|
||||
account_free(d->account);
|
||||
d->account = NULL;
|
||||
|
||||
free(d);
|
||||
}
|
||||
|
||||
|
|
@ -2135,7 +2140,10 @@ static void check_idle_passwords(void)
|
|||
|
||||
for (d = descriptor_list; d; d = next_d) {
|
||||
next_d = d->next;
|
||||
if (STATE(d) != CON_PASSWORD && STATE(d) != CON_GET_NAME && STATE(d) != CON_GET_CONNECT)
|
||||
if (STATE(d) != CON_PASSWORD && STATE(d) != CON_GET_NAME &&
|
||||
STATE(d) != CON_GET_CONNECT && STATE(d) != CON_GET_ACCOUNT &&
|
||||
STATE(d) != CON_ACCOUNT_PASSWORD && STATE(d) != CON_ACCOUNT_NEWPASSWD &&
|
||||
STATE(d) != CON_ACCOUNT_CNFPASSWD)
|
||||
continue;
|
||||
if (!d->idle_tics) {
|
||||
d->idle_tics++;
|
||||
|
|
|
|||
2
src/db.c
2
src/db.c
|
|
@ -3527,6 +3527,8 @@ void free_char(struct char_data *ch)
|
|||
free(ch->player_specials->poofin);
|
||||
if (ch->player_specials->poofout)
|
||||
free(ch->player_specials->poofout);
|
||||
if (ch->player_specials->account_name)
|
||||
free(ch->player_specials->account_name);
|
||||
if (ch->player_specials->saved.completed_quests)
|
||||
free(ch->player_specials->saved.completed_quests);
|
||||
if (GET_HOST(ch))
|
||||
|
|
|
|||
3
src/db.h
3
src/db.h
|
|
@ -34,6 +34,7 @@
|
|||
#define LIB_PLROBJS ":plrobjs:"
|
||||
#define LIB_PLRVARS ":plrvars:"
|
||||
#define LIB_PLRFILES ":plrfiles:"
|
||||
#define LIB_ACCTFILES ":acctfiles:"
|
||||
#define LIB_HOUSE ":house:"
|
||||
#define SLASH ":"
|
||||
#elif defined(CIRCLE_AMIGA) || defined(CIRCLE_UNIX) || defined(CIRCLE_WINDOWS) || defined(CIRCLE_ACORN) || defined(CIRCLE_VMS)
|
||||
|
|
@ -47,6 +48,7 @@
|
|||
#define LIB_PLRVARS "plrvars/"
|
||||
#define LIB_HOUSE "house/"
|
||||
#define LIB_PLRFILES "plrfiles/"
|
||||
#define LIB_ACCTFILES "acctfiles/"
|
||||
#define SLASH "/"
|
||||
#else
|
||||
#error "Unknown path components."
|
||||
|
|
@ -56,6 +58,7 @@
|
|||
#define SUF_TEXT "text"
|
||||
#define SUF_MEM "mem"
|
||||
#define SUF_PLR "plr"
|
||||
#define SUF_ACCT "acc"
|
||||
|
||||
#if defined(CIRCLE_AMIGA)
|
||||
#define EXE_FILE "/bin/circle" /* maybe use argv[0] but it's not reliable */
|
||||
|
|
|
|||
|
|
@ -992,8 +992,8 @@ void extract_char_final(struct char_data *ch)
|
|||
if (GET_POS(ch) == POS_DEAD) {
|
||||
STATE(ch->desc) = CON_CLOSE;
|
||||
} else {
|
||||
STATE(ch->desc) = CON_MENU;
|
||||
write_to_output(ch->desc, "%s", CONFIG_MENU);
|
||||
STATE(ch->desc) = CON_ACCOUNT_MENU;
|
||||
send_account_menu(ch->desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include "ibt.h"
|
||||
#include "mud_event.h"
|
||||
#include "modify.h" /* to ensure page_string is available */
|
||||
#include "accounts.h"
|
||||
|
||||
/* local (file scope) functions */
|
||||
static int perform_dupe_check(struct descriptor_data *d);
|
||||
|
|
@ -1035,6 +1036,25 @@ static int _parse_name(char *arg, char *name)
|
|||
return (0);
|
||||
}
|
||||
|
||||
void send_account_menu(struct descriptor_data *d)
|
||||
{
|
||||
int has_pc;
|
||||
|
||||
if (!d || !d->account)
|
||||
return;
|
||||
|
||||
account_refresh_pc(d->account);
|
||||
has_pc = account_has_alive_pc(d->account);
|
||||
|
||||
write_to_output(d, "\r\nAccount: %s\r\n", d->account->name);
|
||||
if (has_pc)
|
||||
write_to_output(d, "\t(1\t)) Connect to %s.\r\n", d->account->pc_name);
|
||||
else
|
||||
write_to_output(d, "\t(1\t)) Create a new PC.\r\n");
|
||||
write_to_output(d, "\t(0\t)) Exit from tbaMUD.\r\n\r\n"
|
||||
" Make your choice: ");
|
||||
}
|
||||
|
||||
#define RECON 1
|
||||
#define USURP 2
|
||||
#define UNSWITCH 3
|
||||
|
|
@ -1246,6 +1266,9 @@ int enter_player_game (struct descriptor_data *d)
|
|||
if (!d || !d->character)
|
||||
return 0;
|
||||
|
||||
if (!d->account && GET_ACCOUNT(d->character) && *GET_ACCOUNT(d->character))
|
||||
d->account = account_load(GET_ACCOUNT(d->character));
|
||||
|
||||
/* Cache the pfile's saved load room FIRST. */
|
||||
saved_vnum = GET_LOADROOM(d->character);
|
||||
|
||||
|
|
@ -1432,8 +1455,8 @@ void nanny(struct descriptor_data *d, char *arg)
|
|||
}
|
||||
switch (UPPER(*arg)) {
|
||||
case 'C':
|
||||
write_to_output(d, "By what name do you wish to be known? ");
|
||||
STATE(d) = CON_GET_NAME;
|
||||
write_to_output(d, "Account name: ");
|
||||
STATE(d) = CON_GET_ACCOUNT;
|
||||
return;
|
||||
case 'X':
|
||||
write_to_output(d, "Goodbye.\r\n");
|
||||
|
|
@ -1445,14 +1468,61 @@ void nanny(struct descriptor_data *d, char *arg)
|
|||
write_to_output(d, GREETINGS, 0);
|
||||
return;
|
||||
}
|
||||
case CON_GET_ACCOUNT:
|
||||
if (!*arg) {
|
||||
STATE(d) = CON_CLOSE;
|
||||
break;
|
||||
} else {
|
||||
char buf[MAX_INPUT_LENGTH], tmp_name[MAX_INPUT_LENGTH];
|
||||
|
||||
if ((_parse_name(arg, tmp_name)) || strlen(tmp_name) < 2 ||
|
||||
strlen(tmp_name) > MAX_NAME_LENGTH || !valid_name(tmp_name) ||
|
||||
fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) { /* strcpy: OK (mutual MAX_INPUT_LENGTH) */
|
||||
write_to_output(d, "Invalid account name, please try another.\r\nAccount name: ");
|
||||
return;
|
||||
}
|
||||
|
||||
if (d->account) {
|
||||
account_free(d->account);
|
||||
d->account = NULL;
|
||||
}
|
||||
|
||||
d->account = account_load(tmp_name);
|
||||
if (d->account) {
|
||||
write_to_output(d, "Password: ");
|
||||
echo_off(d);
|
||||
d->idle_tics = 0;
|
||||
STATE(d) = CON_ACCOUNT_PASSWORD;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((player_i = get_ptable_by_name(tmp_name)) >= 0 &&
|
||||
!IS_SET(player_table[player_i].flags, PINDEX_DELETED)) {
|
||||
d->account = account_create(tmp_name);
|
||||
account_set_pc(d->account, player_table[player_i].name);
|
||||
write_to_output(d, "An existing character was found. Create an account to link it (\t(Y\t)/\t(N\t))? ");
|
||||
STATE(d) = CON_ACCOUNT_CNFRM;
|
||||
return;
|
||||
}
|
||||
|
||||
d->account = account_create(tmp_name);
|
||||
write_to_output(d, "Create a new account %s (\t(Y\t)/\t(N\t))? ", tmp_name);
|
||||
STATE(d) = CON_ACCOUNT_CNFRM;
|
||||
return;
|
||||
}
|
||||
|
||||
case CON_GET_NAME: /* wait for input of name */
|
||||
if (!d->account) {
|
||||
STATE(d) = CON_CLOSE;
|
||||
return;
|
||||
}
|
||||
if (d->character == NULL) {
|
||||
CREATE(d->character, struct char_data, 1);
|
||||
clear_char(d->character);
|
||||
CREATE(d->character->player_specials, struct player_special_data, 1);
|
||||
|
||||
|
||||
new_mobile_data(d->character);
|
||||
|
||||
|
||||
GET_HOST(d->character) = strdup(d->host);
|
||||
d->character->desc = d;
|
||||
}
|
||||
|
|
@ -1462,72 +1532,125 @@ void nanny(struct descriptor_data *d, char *arg)
|
|||
char buf[MAX_INPUT_LENGTH], tmp_name[MAX_INPUT_LENGTH];
|
||||
|
||||
if ((_parse_name(arg, tmp_name)) || strlen(tmp_name) < 2 ||
|
||||
strlen(tmp_name) > MAX_NAME_LENGTH || !valid_name(tmp_name) ||
|
||||
fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) { /* strcpy: OK (mutual MAX_INPUT_LENGTH) */
|
||||
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
||||
return;
|
||||
strlen(tmp_name) > MAX_NAME_LENGTH || !valid_name(tmp_name) ||
|
||||
fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) { /* strcpy: OK (mutual MAX_INPUT_LENGTH) */
|
||||
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
||||
return;
|
||||
}
|
||||
if ((player_i = load_char(tmp_name, d->character)) > -1) {
|
||||
GET_PFILEPOS(d->character) = player_i;
|
||||
|
||||
if (PLR_FLAGGED(d->character, PLR_DELETED)) {
|
||||
/* Make sure old files are removed so the new player doesn't get the
|
||||
* deleted player's equipment. */
|
||||
if ((player_i = get_ptable_by_name(tmp_name)) >= 0)
|
||||
remove_player(player_i);
|
||||
|
||||
/* We get a false positive from the original deleted character. */
|
||||
free_char(d->character);
|
||||
|
||||
/* Check for multiple creations. */
|
||||
if (!valid_name(tmp_name)) {
|
||||
write_to_output(d, "Invalid name, please try another.\r\nName: ");
|
||||
return;
|
||||
}
|
||||
CREATE(d->character, struct char_data, 1);
|
||||
clear_char(d->character);
|
||||
CREATE(d->character->player_specials, struct player_special_data, 1);
|
||||
|
||||
new_mobile_data(d->character);
|
||||
|
||||
if (GET_HOST(d->character))
|
||||
free(GET_HOST(d->character));
|
||||
GET_HOST(d->character) = strdup(d->host);
|
||||
|
||||
d->character->desc = d;
|
||||
CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
|
||||
strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
|
||||
GET_PFILEPOS(d->character) = player_i;
|
||||
write_to_output(d, "Did I get that right, %s (\t(Y\t)/\t(N\t))? ", tmp_name);
|
||||
STATE(d) = CON_NAME_CNFRM;
|
||||
if ((player_i = get_ptable_by_name(tmp_name)) >= 0) {
|
||||
if (IS_SET(player_table[player_i].flags, PINDEX_DELETED)) {
|
||||
remove_player(player_i);
|
||||
} else {
|
||||
/* undo it just in case they are set */
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING);
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING);
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_CRYO);
|
||||
d->character->player.time.logon = time(0);
|
||||
write_to_output(d, "Password: ");
|
||||
echo_off(d);
|
||||
d->idle_tics = 0;
|
||||
STATE(d) = CON_PASSWORD;
|
||||
}
|
||||
} else {
|
||||
/* player unknown -- make new character */
|
||||
|
||||
/* Check for multiple creations of a character. */
|
||||
if (!valid_name(tmp_name)) {
|
||||
write_to_output(d, "Invalid name, please try another.\r\nBy what name do you wish to be known? ");
|
||||
write_to_output(d, "That name is already taken.\r\nName: ");
|
||||
return;
|
||||
}
|
||||
CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
|
||||
strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
|
||||
|
||||
write_to_output(d, "Did I get that right, %s (\t(Y\t)/\t(N\t))? ", tmp_name);
|
||||
STATE(d) = CON_NAME_CNFRM;
|
||||
}
|
||||
|
||||
if (GET_NAME(d->character))
|
||||
free(GET_NAME(d->character));
|
||||
CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
|
||||
strcpy(d->character->player.name, CAP(tmp_name)); /* strcpy: OK (size checked above) */
|
||||
|
||||
write_to_output(d, "Did I get that right, %s (\t(Y\t)/\t(N\t))? ", tmp_name);
|
||||
STATE(d) = CON_NAME_CNFRM;
|
||||
}
|
||||
break;
|
||||
|
||||
case CON_ACCOUNT_CNFRM:
|
||||
if (UPPER(*arg) == 'Y') {
|
||||
if (isbanned(d->host) >= BAN_NEW) {
|
||||
mudlog(NRM, LVL_GOD, TRUE, "Request for new account %s denied from [%s] (siteban)",
|
||||
d->account ? d->account->name : "<unknown>", d->host);
|
||||
write_to_output(d, "Sorry, new accounts are not allowed from your site!\r\n");
|
||||
STATE(d) = CON_CLOSE;
|
||||
return;
|
||||
}
|
||||
if (circle_restrict) {
|
||||
write_to_output(d, "Sorry, new accounts can't be created at the moment.\r\n");
|
||||
mudlog(NRM, LVL_GOD, TRUE, "Request for new account %s denied from [%s] (wizlock)",
|
||||
d->account ? d->account->name : "<unknown>", d->host);
|
||||
STATE(d) = CON_CLOSE;
|
||||
return;
|
||||
}
|
||||
write_to_output(d, "New account.\r\nGive me a password: ");
|
||||
echo_off(d);
|
||||
STATE(d) = CON_ACCOUNT_NEWPASSWD;
|
||||
} else if (*arg == 'n' || *arg == 'N') {
|
||||
account_free(d->account);
|
||||
d->account = NULL;
|
||||
write_to_output(d, "Okay, what IS it, then?\r\nAccount name: ");
|
||||
STATE(d) = CON_GET_ACCOUNT;
|
||||
} else
|
||||
write_to_output(d, "Please type Yes or No: ");
|
||||
break;
|
||||
|
||||
case CON_ACCOUNT_PASSWORD:
|
||||
echo_on(d);
|
||||
write_to_output(d, "\r\n");
|
||||
|
||||
if (!*arg)
|
||||
STATE(d) = CON_CLOSE;
|
||||
else if (!d->account) {
|
||||
STATE(d) = CON_CLOSE;
|
||||
} else {
|
||||
if (strncmp(CRYPT(arg, d->account->passwd), d->account->passwd, MAX_PWD_LENGTH)) {
|
||||
mudlog(BRF, LVL_GOD, TRUE, "Bad account PW: %s [%s]", d->account->name, d->host);
|
||||
if (++(d->bad_pws) >= CONFIG_MAX_BAD_PWS) {
|
||||
write_to_output(d, "Wrong password... disconnecting.\r\n");
|
||||
STATE(d) = CON_CLOSE;
|
||||
} else {
|
||||
write_to_output(d, "Wrong password.\r\nPassword: ");
|
||||
echo_off(d);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
d->bad_pws = 0;
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
}
|
||||
break;
|
||||
|
||||
case CON_ACCOUNT_NEWPASSWD:
|
||||
if (!*arg || strlen(arg) > MAX_PWD_LENGTH || strlen(arg) < 3 ||
|
||||
!str_cmp(arg, d->account ? d->account->name : "")) {
|
||||
write_to_output(d, "\r\nIllegal password.\r\nPassword: ");
|
||||
return;
|
||||
}
|
||||
strncpy(d->account->passwd, CRYPT(arg, d->account->name), MAX_PWD_LENGTH);
|
||||
d->account->passwd[MAX_PWD_LENGTH] = '\0';
|
||||
|
||||
write_to_output(d, "\r\nPlease retype password: ");
|
||||
STATE(d) = CON_ACCOUNT_CNFPASSWD;
|
||||
break;
|
||||
|
||||
case CON_ACCOUNT_CNFPASSWD:
|
||||
if (strncmp(CRYPT(arg, d->account->passwd), d->account->passwd, MAX_PWD_LENGTH)) {
|
||||
write_to_output(d, "\r\nPasswords don't match... start over.\r\nPassword: ");
|
||||
STATE(d) = CON_ACCOUNT_NEWPASSWD;
|
||||
return;
|
||||
}
|
||||
echo_on(d);
|
||||
|
||||
write_to_output(d, "\r\nEmail address (optional, press Enter to skip): ");
|
||||
STATE(d) = CON_ACCOUNT_EMAIL;
|
||||
break;
|
||||
|
||||
case CON_ACCOUNT_EMAIL:
|
||||
if (d->account) {
|
||||
if (d->account->email)
|
||||
free(d->account->email);
|
||||
d->account->email = NULL;
|
||||
if (*arg)
|
||||
d->account->email = strdup(arg);
|
||||
account_save(d->account);
|
||||
}
|
||||
write_to_output(d, "\r\nAccount created.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
break;
|
||||
|
||||
case CON_NAME_CNFRM: /* wait for conf. of new name */
|
||||
if (UPPER(*arg) == 'Y') {
|
||||
if (isbanned(d->host) >= BAN_NEW) {
|
||||
|
|
@ -1543,11 +1666,13 @@ void nanny(struct descriptor_data *d, char *arg)
|
|||
return;
|
||||
}
|
||||
perform_new_char_dupe_check(d);
|
||||
write_to_output(d, "New character.\r\nGive me a password for %s: ", GET_PC_NAME(d->character));
|
||||
echo_off(d);
|
||||
STATE(d) = CON_NEWPASSWD;
|
||||
if (GET_ACCOUNT(d->character))
|
||||
free(GET_ACCOUNT(d->character));
|
||||
GET_ACCOUNT(d->character) = d->account ? strdup(d->account->name) : NULL;
|
||||
write_to_output(d, "New character.\r\nWhat is your sex (\t(M\t)/\t(F\t))? ");
|
||||
STATE(d) = CON_QSEX;
|
||||
} else if (*arg == 'n' || *arg == 'N') {
|
||||
write_to_output(d, "Okay, what IS it, then?\r\nBy what name do you wish to be known? ");
|
||||
write_to_output(d, "Okay, what IS it, then?\r\nName: ");
|
||||
free(d->character->player.name);
|
||||
d->character->player.name = NULL;
|
||||
STATE(d) = CON_GET_NAME;
|
||||
|
|
@ -1671,8 +1796,9 @@ void nanny(struct descriptor_data *d, char *arg)
|
|||
STATE(d) = CON_QSEX;
|
||||
} else {
|
||||
save_char(d->character);
|
||||
write_to_output(d, "\r\nDone.\r\n%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
write_to_output(d, "\r\nDone.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
@ -1715,8 +1841,17 @@ case CON_QCLASS:
|
|||
|
||||
/* Initialize base stats, starting level, etc. */
|
||||
init_char(d->character);
|
||||
if (d->account && d->account->name) {
|
||||
if (GET_ACCOUNT(d->character))
|
||||
free(GET_ACCOUNT(d->character));
|
||||
GET_ACCOUNT(d->character) = strdup(d->account->name);
|
||||
}
|
||||
save_char(d->character);
|
||||
save_player_index();
|
||||
if (d->account) {
|
||||
account_set_pc(d->account, GET_NAME(d->character));
|
||||
account_save(d->account);
|
||||
}
|
||||
|
||||
/* Log and register early so new players are tracked immediately */
|
||||
GET_PREF(d->character) = rand_number(1, 128000);
|
||||
|
|
@ -1807,13 +1942,13 @@ case CON_QCLASS:
|
|||
write_to_output(d,
|
||||
"\r\nBefore stepping into Miranthas, share a bit of your character's background.\r\n"
|
||||
"Guideline: aim for at least four lines that hint at where they came from,\r\n"
|
||||
"who shaped them, and why they now walk the Tyr region. Touch on things like:\r\n"
|
||||
"who shaped them, and why they now walk the Caleran region. Touch on things like:\r\n"
|
||||
" - The city-state, tribe, or caravan that claimed them.\r\n"
|
||||
" - Mentors, slavers, or patrons who left a mark.\r\n"
|
||||
" - A defining hardship, triumph, oath, or secret.\r\n"
|
||||
" - The goal, vengeance, or hope that drives them back into the wastes.\r\n"
|
||||
"\r\nExample 1:\r\n"
|
||||
" Raised beneath the ziggurat of Tyr, I learned to barter gossip between\r\n"
|
||||
" Raised beneath the ziggurat of Caleran, I learned to barter gossip between\r\n"
|
||||
" templars and gladiators just to stay alive. Freedom came when Kalak fell,\r\n"
|
||||
" but the slave-scar on my shoulder still aches. I now search the desert\r\n"
|
||||
" for the relic my clutch mates died protecting, hoping to buy their kin peace.\r\n"
|
||||
|
|
@ -1825,7 +1960,7 @@ case CON_QCLASS:
|
|||
"\r\nExample 3:\r\n"
|
||||
" Born outside Raam, I was tempered by obsidian shards and psionic murmurs.\r\n"
|
||||
" A defiler ruined our oasis, so I swore to hound such spell-scars wherever\r\n"
|
||||
" they bloom. Rumor of a hidden well near Tyr is the lone hope that guides me.\r\n"
|
||||
" they bloom. Rumor of a hidden well near Caleran is the lone hope that guides me.\r\n"
|
||||
"\r\nType your background now. Use '/s' on a blank line when you finish.\r\n"
|
||||
"If you'd rather keep it secret, just save immediately and we'll note the mystery.\r\n\r\n");
|
||||
d->backstr = NULL;
|
||||
|
|
@ -1847,78 +1982,173 @@ case CON_QCLASS:
|
|||
break;
|
||||
|
||||
case CON_RMOTD: /* read CR after printing motd */
|
||||
write_to_output(d, "%s", CONFIG_MENU);
|
||||
if (!d->character) {
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
break;
|
||||
}
|
||||
if (!d->account && GET_ACCOUNT(d->character) && *GET_ACCOUNT(d->character))
|
||||
d->account = account_load(GET_ACCOUNT(d->character));
|
||||
add_llog_entry(d->character, LAST_CONNECT);
|
||||
STATE(d) = CON_MENU;
|
||||
|
||||
load_result = enter_player_game(d);
|
||||
send_to_char(d->character, "%s", CONFIG_WELC_MESSG);
|
||||
|
||||
save_char(d->character);
|
||||
|
||||
greet_mtrigger(d->character, -1);
|
||||
greet_memory_mtrigger(d->character);
|
||||
|
||||
act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
|
||||
|
||||
STATE(d) = CON_PLAYING;
|
||||
MXPSendTag(d, "<VERSION>");
|
||||
|
||||
if (GET_LEVEL(d->character) == 0) {
|
||||
do_start(d->character);
|
||||
send_to_char(d->character, "%s", CONFIG_START_MESSG);
|
||||
}
|
||||
|
||||
look_at_room(d->character, 0);
|
||||
if (has_mail(GET_IDNUM(d->character)))
|
||||
send_to_char(d->character, "You have mail waiting.\r\n");
|
||||
|
||||
d->has_prompt = 0;
|
||||
/* We've updated to 3.1 - some bits might be set wrongly: */
|
||||
REMOVE_BIT_AR(PRF_FLAGS(d->character), PRF_BUILDWALK);
|
||||
break;
|
||||
|
||||
case CON_MENU: { /* get selection from main menu */
|
||||
case CON_ACCOUNT_MENU: {
|
||||
int has_pc;
|
||||
|
||||
if (!d->account) {
|
||||
STATE(d) = CON_CLOSE;
|
||||
break;
|
||||
}
|
||||
|
||||
account_refresh_pc(d->account);
|
||||
has_pc = account_has_alive_pc(d->account);
|
||||
|
||||
switch (*arg) {
|
||||
case '0':
|
||||
write_to_output(d, "Goodbye.\r\n");
|
||||
add_llog_entry(d->character, LAST_QUIT);
|
||||
if (d->character)
|
||||
add_llog_entry(d->character, LAST_QUIT);
|
||||
STATE(d) = CON_CLOSE;
|
||||
break;
|
||||
|
||||
case '1':
|
||||
/* Proceed into the world */
|
||||
load_result = enter_player_game(d);
|
||||
send_to_char(d->character, "%s", CONFIG_WELC_MESSG);
|
||||
if (has_pc) {
|
||||
if (d->character) {
|
||||
free_char(d->character);
|
||||
d->character = NULL;
|
||||
}
|
||||
CREATE(d->character, struct char_data, 1);
|
||||
clear_char(d->character);
|
||||
CREATE(d->character->player_specials, struct player_special_data, 1);
|
||||
new_mobile_data(d->character);
|
||||
|
||||
save_char(d->character);
|
||||
GET_HOST(d->character) = strdup(d->host);
|
||||
d->character->desc = d;
|
||||
|
||||
greet_mtrigger(d->character, -1);
|
||||
greet_memory_mtrigger(d->character);
|
||||
if ((player_i = load_char(d->account->pc_name, d->character)) < 0) {
|
||||
write_to_output(d, "Could not load that character.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
break;
|
||||
}
|
||||
GET_PFILEPOS(d->character) = player_i;
|
||||
|
||||
act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);
|
||||
if (GET_ACCOUNT(d->character) && str_cmp(GET_ACCOUNT(d->character), d->account->name)) {
|
||||
write_to_output(d, "That character does not belong to this account.\r\n");
|
||||
free_char(d->character);
|
||||
d->character = NULL;
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
break;
|
||||
}
|
||||
if (!GET_ACCOUNT(d->character) && d->account->name) {
|
||||
GET_ACCOUNT(d->character) = strdup(d->account->name);
|
||||
save_char(d->character);
|
||||
}
|
||||
|
||||
STATE(d) = CON_PLAYING;
|
||||
MXPSendTag(d, "<VERSION>");
|
||||
/* undo it just in case they are set */
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_WRITING);
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_MAILING);
|
||||
REMOVE_BIT_AR(PLR_FLAGS(d->character), PLR_CRYO);
|
||||
d->character->player.time.logon = time(0);
|
||||
|
||||
if (GET_LEVEL(d->character) == 0) {
|
||||
do_start(d->character);
|
||||
send_to_char(d->character, "%s", CONFIG_START_MESSG);
|
||||
if (isbanned(d->host) == BAN_SELECT &&
|
||||
!PLR_FLAGGED(d->character, PLR_SITEOK)) {
|
||||
write_to_output(d, "Sorry, this char has not been cleared for login from your site!\r\n");
|
||||
STATE(d) = CON_CLOSE;
|
||||
mudlog(NRM, LVL_GOD, TRUE, "Connection attempt for %s denied from %s",
|
||||
GET_NAME(d->character), d->host);
|
||||
return;
|
||||
}
|
||||
if (GET_LEVEL(d->character) < circle_restrict) {
|
||||
write_to_output(d, "The game is temporarily restricted.. try again later.\r\n");
|
||||
STATE(d) = CON_CLOSE;
|
||||
mudlog(NRM, LVL_GOD, TRUE, "Request for login denied for %s [%s] (wizlock)",
|
||||
GET_NAME(d->character), d->host);
|
||||
return;
|
||||
}
|
||||
|
||||
if (perform_dupe_check(d))
|
||||
return;
|
||||
|
||||
if (GET_LEVEL(d->character) >= LVL_IMMORT)
|
||||
write_to_output(d, "%s", imotd);
|
||||
else
|
||||
write_to_output(d, "%s", motd);
|
||||
|
||||
if (GET_INVIS_LEV(d->character))
|
||||
mudlog(BRF, MAX(LVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE,
|
||||
"%s has connected. (invis %d)", GET_NAME(d->character),
|
||||
GET_INVIS_LEV(d->character));
|
||||
else
|
||||
mudlog(BRF, LVL_IMMORT, TRUE, "%s has connected.", GET_NAME(d->character));
|
||||
|
||||
if (AddRecentPlayer(GET_NAME(d->character), d->host, FALSE, FALSE) == FALSE) {
|
||||
mudlog(BRF, MAX(LVL_IMMORT, GET_INVIS_LEV(d->character)), TRUE,
|
||||
"Failure to AddRecentPlayer (returned FALSE).");
|
||||
}
|
||||
|
||||
write_to_output(d, "\r\n*** PRESS RETURN: ");
|
||||
STATE(d) = CON_RMOTD;
|
||||
} else {
|
||||
if (d->character) {
|
||||
free_char(d->character);
|
||||
d->character = NULL;
|
||||
}
|
||||
write_to_output(d, "By what name do you wish to be known? ");
|
||||
STATE(d) = CON_GET_NAME;
|
||||
}
|
||||
|
||||
look_at_room(d->character, 0);
|
||||
if (has_mail(GET_IDNUM(d->character)))
|
||||
send_to_char(d->character, "You have mail waiting.\r\n");
|
||||
|
||||
d->has_prompt = 0;
|
||||
/* We've updated to 3.1 - some bits might be set wrongly: */
|
||||
REMOVE_BIT_AR(PRF_FLAGS(d->character), PRF_BUILDWALK);
|
||||
break;
|
||||
|
||||
case '2':
|
||||
page_string(d, background, 0);
|
||||
STATE(d) = CON_RMOTD;
|
||||
break;
|
||||
|
||||
case '3':
|
||||
write_to_output(d, "\r\nEnter your old password: ");
|
||||
echo_off(d);
|
||||
STATE(d) = CON_CHPWD_GETOLD;
|
||||
break;
|
||||
|
||||
case '4':
|
||||
write_to_output(d, "\r\nEnter your password for verification: ");
|
||||
echo_off(d);
|
||||
STATE(d) = CON_DELCNF1;
|
||||
break;
|
||||
|
||||
default:
|
||||
write_to_output(d, "\r\nThat's not a menu choice!\r\n%s", CONFIG_MENU);
|
||||
write_to_output(d, "\r\nThat's not a menu choice!\r\n");
|
||||
send_account_menu(d);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CON_MENU: { /* get selection from main menu */
|
||||
if (!d->account) {
|
||||
write_to_output(d, "No account loaded.\r\n");
|
||||
STATE(d) = CON_CLOSE;
|
||||
break;
|
||||
}
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
break;
|
||||
}
|
||||
|
||||
case CON_CHPWD_GETOLD:
|
||||
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
|
||||
echo_on(d);
|
||||
write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
write_to_output(d, "\r\nIncorrect password.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
} else {
|
||||
write_to_output(d, "\r\nEnter a new password: ");
|
||||
STATE(d) = CON_CHPWD_GETNEW;
|
||||
|
|
@ -1928,8 +2158,9 @@ case CON_QCLASS:
|
|||
case CON_DELCNF1:
|
||||
echo_on(d);
|
||||
if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
|
||||
write_to_output(d, "\r\nIncorrect password.\r\n%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
write_to_output(d, "\r\nIncorrect password.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
} else {
|
||||
write_to_output(d, "\r\nYOU ARE ABOUT TO DELETE THIS CHARACTER PERMANENTLY.\r\n"
|
||||
"ARE YOU ABSOLUTELY SURE?\r\n\r\n"
|
||||
|
|
@ -1965,8 +2196,9 @@ case CON_QCLASS:
|
|||
STATE(d) = CON_CLOSE;
|
||||
return;
|
||||
} else {
|
||||
write_to_output(d, "\r\nCharacter not deleted.\r\n%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
write_to_output(d, "\r\nCharacter not deleted.\r\n");
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
}
|
||||
break;
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ int fill_word(char *argument);
|
|||
int reserved_word(char *argument);
|
||||
void half_chop(char *string, char *arg1, char *arg2);
|
||||
void nanny(struct descriptor_data *d, char *arg);
|
||||
void send_account_menu(struct descriptor_data *d);
|
||||
int is_abbrev(const char *arg1, const char *arg2);
|
||||
int is_number(const char *str);
|
||||
int find_command(const char *command);
|
||||
|
|
|
|||
14
src/modify.c
14
src/modify.c
|
|
@ -312,13 +312,13 @@ static void exdesc_string_cleanup(struct descriptor_data *d, int action)
|
|||
write_to_output(d,
|
||||
"\r\nBefore stepping into Miranthas, share a bit of your character's background.\r\n"
|
||||
"Guideline: aim for at least four lines that hint at where they came from,\r\n"
|
||||
"who shaped them, and why they now walk the Tyr region. Touch on things like:\r\n"
|
||||
"who shaped them, and why they now walk the Caleran region. Touch on things like:\r\n"
|
||||
" - The city-state, tribe, or caravan that claimed them.\r\n"
|
||||
" - Mentors, slavers, or patrons who left a mark.\r\n"
|
||||
" - A defining hardship, triumph, oath, or secret.\r\n"
|
||||
" - The goal, vengeance, or hope that drives them back into the wastes.\r\n"
|
||||
"\r\nExample 1:\r\n"
|
||||
" Raised beneath the ziggurat of Tyr, I learned to barter gossip between\r\n"
|
||||
" Raised beneath the ziggurat of Caleran, I learned to barter gossip between\r\n"
|
||||
" templars and gladiators just to stay alive. Freedom came when Kalak fell,\r\n"
|
||||
" but the slave-scar on my shoulder still aches. I now search the desert\r\n"
|
||||
" for the relic my clutch mates died protecting, hoping to buy their kin peace.\r\n"
|
||||
|
|
@ -330,7 +330,7 @@ static void exdesc_string_cleanup(struct descriptor_data *d, int action)
|
|||
"\r\nExample 3:\r\n"
|
||||
" Born outside Raam, I was tempered by obsidian shards and psionic murmurs.\r\n"
|
||||
" A defiler ruined our oasis, so I swore to hound such spell-scars wherever\r\n"
|
||||
" they bloom. Rumor of a hidden well near Tyr is the lone hope that guides me.\r\n"
|
||||
" they bloom. Rumor of a hidden well near Caleran is the lone hope that guides me.\r\n"
|
||||
"\r\nType your background now. Use '/s' on a blank line when you finish.\r\n"
|
||||
"If you'd rather keep it secret, just save immediately and we'll note the mystery.\r\n\r\n");
|
||||
d->backstr = NULL;
|
||||
|
|
@ -343,8 +343,8 @@ static void exdesc_string_cleanup(struct descriptor_data *d, int action)
|
|||
return;
|
||||
}
|
||||
|
||||
write_to_output(d, "%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
}
|
||||
|
||||
static void background_string_cleanup(struct descriptor_data *d, int action)
|
||||
|
|
@ -369,8 +369,8 @@ static void background_string_cleanup(struct descriptor_data *d, int action)
|
|||
return;
|
||||
}
|
||||
|
||||
write_to_output(d, "%s", CONFIG_MENU);
|
||||
STATE(d) = CON_MENU;
|
||||
send_account_menu(d);
|
||||
STATE(d) = CON_ACCOUNT_MENU;
|
||||
}
|
||||
|
||||
/* By Michael Buselli. Traverse down the string until the begining of the next
|
||||
|
|
|
|||
|
|
@ -297,6 +297,10 @@ int load_char(const char *name, struct char_data *ch)
|
|||
GET_NUM_QUESTS(ch) = PFDEF_COMPQUESTS;
|
||||
GET_LAST_MOTD(ch) = PFDEF_LASTMOTD;
|
||||
GET_LAST_NEWS(ch) = PFDEF_LASTNEWS;
|
||||
if (GET_ACCOUNT(ch)) {
|
||||
free(GET_ACCOUNT(ch));
|
||||
GET_ACCOUNT(ch) = NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < AF_ARRAY_MAX; i++)
|
||||
AFF_FLAGS(ch)[i] = PFDEF_AFFFLAGS;
|
||||
|
|
@ -311,6 +315,11 @@ int load_char(const char *name, struct char_data *ch)
|
|||
switch (*tag) {
|
||||
case 'A':
|
||||
if (!strcmp(tag, "Ac ")) GET_AC(ch) = atoi(line);
|
||||
else if (!strcmp(tag, "Acct")) {
|
||||
if (GET_ACCOUNT(ch))
|
||||
free(GET_ACCOUNT(ch));
|
||||
GET_ACCOUNT(ch) = strdup(line);
|
||||
}
|
||||
else if (!strcmp(tag, "Act ")) {
|
||||
if (sscanf(line, "%s %s %s %s", f1, f2, f3, f4) == 4) {
|
||||
PLR_FLAGS(ch)[0] = asciiflag_conv(f1);
|
||||
|
|
@ -590,6 +599,7 @@ void save_char(struct char_data * ch)
|
|||
if (GET_NAME(ch)) fprintf(fl, "Name: %s\n", GET_NAME(ch));
|
||||
if (GET_SHORT_DESC(ch) && *GET_SHORT_DESC(ch)) fprintf(fl, "Sdsc: %s\n", GET_SHORT_DESC(ch));
|
||||
if (GET_PASSWD(ch)) fprintf(fl, "Pass: %s\n", GET_PASSWD(ch));
|
||||
if (GET_ACCOUNT(ch) && *GET_ACCOUNT(ch)) fprintf(fl, "Acct: %s\n", GET_ACCOUNT(ch));
|
||||
if (ch->player.description && *ch->player.description) {
|
||||
strcpy(buf, ch->player.description);
|
||||
strip_cr(buf);
|
||||
|
|
|
|||
|
|
@ -341,6 +341,13 @@
|
|||
#define CON_PLR_BACKGROUND 33 /**< Entering a new character background */
|
||||
#define CON_GET_PROTOCOL 33 /**< Used at log-in while attempting to get protocols > */
|
||||
#define CON_GET_CONNECT 34 /**< Login connect/disconnect menu */
|
||||
#define CON_GET_ACCOUNT 35 /**< Login with account name */
|
||||
#define CON_ACCOUNT_CNFRM 36 /**< New account, confirm name */
|
||||
#define CON_ACCOUNT_PASSWORD 37 /**< Login with account password */
|
||||
#define CON_ACCOUNT_NEWPASSWD 38 /**< New account, create password */
|
||||
#define CON_ACCOUNT_CNFPASSWD 39 /**< New account, confirm password */
|
||||
#define CON_ACCOUNT_EMAIL 40 /**< New account, optional email */
|
||||
#define CON_ACCOUNT_MENU 41 /**< Account main menu */
|
||||
|
||||
/* OLC States range - used by IS_IN_OLC and IS_PLAYING */
|
||||
#define FIRST_OLC_STATE CON_OEDIT /**< The first CON_ state that is an OLC */
|
||||
|
|
@ -1022,10 +1029,20 @@ struct player_special_data
|
|||
void *last_olc_targ; /**< ? Currently Unused ? */
|
||||
int last_olc_mode; /**< ? Currently Unused ? */
|
||||
char *host; /**< Resolved hostname, or ip, for player. */
|
||||
char *account_name; /**< Account name owning this PC. */
|
||||
int buildwalk_sector; /**< Default sector type for buildwalk */
|
||||
struct scan_result_data *scan_results; /**< Hidden figures this player has spotted */
|
||||
};
|
||||
|
||||
/** Account data stored separately from character data. */
|
||||
struct account_data
|
||||
{
|
||||
char *name; /**< Account username */
|
||||
char passwd[MAX_PWD_LENGTH+1]; /**< Account password (hashed) */
|
||||
char *email; /**< Optional email address */
|
||||
char *pc_name; /**< Attached PC name, if any */
|
||||
};
|
||||
|
||||
/** Special data used by NPCs, not PCs */
|
||||
struct mob_special_data
|
||||
{
|
||||
|
|
@ -1158,6 +1175,7 @@ struct descriptor_data
|
|||
int bufspace; /**< space left in the output buffer */
|
||||
struct txt_block *large_outbuf; /**< ptr to large buffer, if we need it */
|
||||
struct txt_q input; /**< q of unprocessed input */
|
||||
struct account_data *account; /**< Active account session data */
|
||||
struct char_data *character; /**< linked to char */
|
||||
struct char_data *original; /**< original char if switched */
|
||||
struct descriptor_data *snooping; /**< Who is this char snooping */
|
||||
|
|
|
|||
|
|
@ -787,6 +787,10 @@ int get_filename(char *filename, size_t fbufsize, int mode, const char *orig_nam
|
|||
prefix = LIB_PLRFILES;
|
||||
suffix = SUF_PLR;
|
||||
break;
|
||||
case ACCT_FILE:
|
||||
prefix = LIB_ACCTFILES;
|
||||
suffix = SUF_ACCT;
|
||||
break;
|
||||
default:
|
||||
return (0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,8 +211,9 @@ void char_from_furniture(struct char_data *ch);
|
|||
#define ETEXT_FILE 1 /**< ???? */
|
||||
#define SCRIPT_VARS_FILE 2 /**< Reference to a global variable file. */
|
||||
#define PLR_FILE 3 /**< The standard player file */
|
||||
#define ACCT_FILE 4 /**< The standard account file */
|
||||
|
||||
#define MAX_FILES 4 /**< Max number of files types vailable */
|
||||
#define MAX_FILES 4 /**< Max number of player-owned file types available */
|
||||
|
||||
/* breadth-first searching for graph function (tracking, etc) */
|
||||
#define BFS_ERROR (-1) /**< Error in the search. */
|
||||
|
|
@ -543,6 +544,7 @@ do \
|
|||
#define GET_LEVEL(ch) ((ch)->player.level)
|
||||
/** Password of PC. */
|
||||
#define GET_PASSWD(ch) ((ch)->player.passwd)
|
||||
#define GET_ACCOUNT(ch) CHECK_PLAYER_SPECIAL((ch), ((ch)->player_specials->account_name))
|
||||
/** The player file position of PC. */
|
||||
#define GET_PFILEPOS(ch)((ch)->pfilepos)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue