/**************************************************************************
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer, *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe. *
* *
* Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael *
* Chastain, Michael Quan, and Mitchell Tse. *
* *
* In order to use any part of this Merc Diku Mud, you must comply with *
* both the original Diku license in 'license.doc' as well the Merc *
* license in 'license.txt'. In particular, you may not remove either of *
* these copyright notices. *
* *
* Much time and thought has gone into this software and you are *
* benefiting. We hope that you share your changes too. What goes *
* around, comes around. *
***************************************************************************
* ROM 2.4 is copyright 1993-1998 Russ Taylor *
* ROM has been brought to you by the ROM consortium *
* Russ Taylor (rtaylor@hypercube.org) *
* Gabrielle Taylor (gtaylor@hypercube.org) *
* Brian Moore (zump@rom.org) *
* By using this code, you have agreed to follow the terms of the *
* ROM license, in the file Rom24/doc/rom.license *
***************************************************************************
* 1stMud ROM Derivative (c) 2001-2004 by Markanth *
* http://www.firstmud.com/ <markanth@firstmud.com> *
* By using this code you have agreed to follow the term of *
* the 1stMud license in ../doc/1stMud/LICENSE *
***************************************************************************/
#include "merc.h"
#include "interp.h"
#include "recycle.h"
#include "tables.h"
#include "olc.h"
#include "telnet.h"
#include "data_table.h"
#include "vnums.h"
Proto(void game_loop, (SOCKET));
Proto(SOCKET init_socket, (int));
Proto(void init_descriptor, (int));
Proto(int main, (int, char **));
Proto(void nanny, (Descriptor *, const char *));
Proto(bool process_output, (Descriptor *, bool));
Proto(void read_from_buffer, (Descriptor *));
Proto(void stop_idling, (CharData *));
Proto(void set_game_levels, (int, int));
Proto(bool check_directories, (const char *));
Proto(bool create_directories, (void));
Proto(int print_stripped_client_code, (Descriptor *, const char *, int));
Proto(void log_release_held_logs, (void));
Proto(void log_hold_till_commandline_options_parsed, (void));
const char *whoami(void)
{
#ifdef WIN32
static char username[UNLEN + 1];
unsigned long szusername = UNLEN + 1;
if (GetUserName(username, &szusername))
{
return (username);
}
#elif defined HAVE_GETUID && defined HAVE_GETPWUID
struct passwd *pwd;
uid_t uid;
uid = getuid();
if ((pwd = getpwuid(uid)))
{
return (pwd->pw_name);
}
#endif
return "unknown";
}
char *get_platform_info(void)
{
static char buf[2048];
#ifdef WIN32
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(osvi);
GetVersionEx(&osvi);
sprintf(buf, "%s v%d.%d.%d [%s]",
osvi.dwPlatformId ==
VER_PLATFORM_WIN32s ? "Win32s" : osvi.dwPlatformId ==
VER_PLATFORM_WIN32_WINDOWS ? "Windows9x" : osvi.dwPlatformId ==
VER_PLATFORM_WIN32_NT ? "WindowsNT" : FORMATF("Unknown(%d)",
osvi.dwPlatformId),
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber,
osvi.szCSDVersion);
#elif defined HAVE_SYS_UTSNAME_H
struct utsname name;
if (uname(&name) == -1)
{
sprintf(buf, "Unknown-uname_error%d", errno);
}
else
{
sprintf(buf,
"sysname='%s' nodename='%s' "
"release='%s' version='%s' machine='%s'", name.sysname,
name.nodename, name.release, name.version, name.machine);
}
#if defined HAVE_SYS_SYSCTL_H && defined CTL_KERN && defined KERN_VERSION
int mib[2];
char kernver[512];
size_t len;
mib[0] = CTL_KERN;
mib[1] = KERN_VERSION;
len = sizeof(kernver);
if (sysctl(mib, 2, &kernver, &len, NULL, 0) == 0)
{
kernver[sizeof(kernver) - 1] = '\0';
strcat(buf, " kernver='");
strcat(buf, strip_cr(kernver));
strcat(buf, "'");
}
#endif
#elif defined __CYGWIN__
strcpy(buf, "Cygwin.");
#else
strcpy(buf, "Unknown.");
#endif
return buf;
}
time_t getcurrenttime(void)
{
struct timeval last_time;
gettimeofday(&last_time, NULL);
current_time = (time_t) last_time.tv_sec;
return current_time;
}
void sleep_seconds(int seconds)
{
#ifdef WIN32
Sleep(seconds * 1000);
#else
sleep(seconds);
#endif
}
#ifdef WIN32
int winsock_error = NO_ERROR;
#define WIN32_USE_WINSOCK2
#endif
void init_network(void)
{
#ifdef WIN32
#ifdef WIN32_USE_WINSOCK2
WORD wVersionRequested = MAKEWORD(2, 0);
#else
WORD wVersionRequested = MAKEWORD(1, 1);
#endif
WSADATA wsaData;
if (winsock_error != NO_ERROR)
return;
if ((winsock_error = WSAStartup(wVersionRequested, &wsaData)) != NO_ERROR)
{
log_string("Couldn't initialize winsock.");
exit(1);
}
#endif
}
void close_network(void)
{
#ifdef WIN32
if (winsock_error == NO_ERROR && crs_info.status != CRS_COPYOVER)
{
WSACleanup();
winsock_error = SOCKET_ERROR;
}
#endif
}
void init_globals(char *exename)
{
char *p, d[2] = DIR_SYM;
#ifndef SERVER_HOSTNAME
if (gethostname(HOSTNAME, sizeof(HOSTNAME)) == -1 || NullStr(HOSTNAME))
strcpy(HOSTNAME, "localhost");
#else
strcpy(HOSTNAME, SERVER_HOSTNAME);
#endif
if (!getcwd(CWDIR, sizeof(CWDIR)) || NullStr(CWDIR))
strcpy(CWDIR, BIN_DIR);
if ((p = strrchr(exename, d[0])) != NULL)
p++;
else
p = exename;
if (p[0] != d[0])
sprintf(EXE_FILE, BIN_DIR "%s", p);
else
strcpy(EXE_FILE, p);
strcpy(UNAME, whoami());
}
EXTERN bool log_hold_log_string_core_stdout_restore_value;
int parsed_mainport;
void cmdline_help(char **argv)
{
log_string("Commands:");
log_string("-v, --version displays version info");
log_string
("-r, --relvl [old max] [new max] change max level on game data");
log_string
("-s, --signal <all|#sig> disables signal handling on #sig number");
log_string("-nb, --nobackground don't run in daemon mode");
log_string("-nl, --nologfile don't write to a logfile.");
log_string
("-q, --quiet quiet mode, no loggin to stdout.");
log_string
("-lc, --logconsole always log to the console (win32 default).");
log_string("--createdirs create missing directories");
log_string("Startup Syntax:");
logf("%s [#port] sets the port number", argv[0]);
log_string("Where the port number is in the range 1024 to 65535");
log_string("Default port can be configured in " MUD_FILE ".");
}
flag_t parsed_cmdline_options;
bool parse_cmdline_options(int argc, char **argv)
{
int i;
mainport = 0;
parsed_mainport = 0;
#ifdef WIN32
parsed_cmdline_options =
CMDLINE_NO_BACKGROUND_PROCESS | CMDLINE_LOG_CONSOLE;
#else
parsed_cmdline_options = 0;
#endif
for (i = 1; i < argc; i++)
{
if (!str_cmp("-q", argv[i]) || !str_cmp("--quiet", argv[i]))
{
SetBit(parsed_cmdline_options, CMDLINE_QUIET);
log_hold_log_string_core_stdout_restore_value = false;
log_string("Starting in quiet mode, no logging to stdout.");
if (IsSet(parsed_cmdline_options, CMDLINE_LOG_CONSOLE))
{
log_string
("The quiet mode doesn't make much sense if the log console option has been selected.");
return false;
}
}
else if (!str_cmp(argv[i], "-nb")
|| !str_cmp(argv[i], "--nobackground"))
{
SetBit(parsed_cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS);
log_string("Disabling daemon mode...");
}
else if (!str_cmp(argv[i], "-nl") || !str_cmp(argv[i], "--nologfile"))
{
SetBit(parsed_cmdline_options, CMDLINE_NO_LOGFILE);
log_string("Disabling use of a log file...");
}
else if (!str_cmp(argv[i], "lc") || !str_cmp(argv[i], "--logconsole"))
{
SetBit(parsed_cmdline_options, CMDLINE_LOG_CONSOLE);
log_string("Logging to console...");
if (IsSet(parsed_cmdline_options, CMDLINE_QUIET))
{
log_string
("The log console option doesn't make much sense if the quiet option has been selected.");
log_hold_log_string_core_stdout_restore_value = true;
return false;
}
}
else if (!str_cmp("-nolc", argv[i])
|| !str_cmp("--nologconsole", argv[i]))
{
SetBit(parsed_cmdline_options, CMDLINE_LOG_CONSOLE);
log_string("Logging to console disabled...");
}
else if (!str_cmp("-f", argv[i]) || !str_cmp("--foreground", argv[i]))
{
SetBit(parsed_cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS);
SetBit(parsed_cmdline_options, CMDLINE_LOG_CONSOLE);
log_string("Running mud in foreground...");
if (IsSet(parsed_cmdline_options, CMDLINE_QUIET))
{
log_string
("The foreground option doesn't make much sense if the quiet option has been selected.");
log_string
("Try using -q -nb if you want the mud to run in the foreground with no console logging.");
log_hold_log_string_core_stdout_restore_value = true;
return false;
}
}
else if (!str_cmp("--startup-script", argv[i]))
{
SetBit(parsed_cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS);
SetBit(parsed_cmdline_options, CMDLINE_STARTUP_SCRIPT);
}
else if (!str_cmp(argv[i], "-s") || !str_cmp(argv[i], "--signal"))
{
bool found = false, all_sigs = false;
int s;
char buf[MSL];
i++;
if (!str_cmp(argv[i], "all"))
{
all_sigs = true;
log_string("All signal handling disabled...");
}
buf[0] = NUL;
for (s = 0; sig_table[s].name != NULL; s++)
{
if (all_sigs || !str_prefix(argv[i], sig_table[s].name))
{
SetBit(mud_info.disabled_signals,
MakeBit(sig_table[s].sig));
found = true;
if (!all_sigs)
{
logf("Disabling %s signal handling...",
sig_table[s].name);
break;
}
}
strcat(buf, " ");
strcat(buf, sig_table[s].name);
}
if (!found)
{
logf("Usage: %s %s <#sig>|all", argv[0], argv[i]);
logf("Available signals:%s", buf);
return false;
}
else
SetBit(parsed_cmdline_options, CMDLINE_DISABLE_SIGNALS);
}
else if (!str_cmp(argv[i], "-v") || !str_cmp(argv[i], "--version"))
{
logf(MUDSTRING ": Compiled on " __DATE__ " at " __TIME__ ".");
return false;
}
else if (!str_cmp(argv[i], "-c") || !str_cmp(argv[i], "--copyover"))
{
crs_info.status = CRS_COPYOVER;
mud_control = atoi(argv[++i]);
parsed_mainport = atoi(argv[++i]);
#ifndef DISABLE_I3
I3_control = atoi(argv[++i]);
#else
i++;
#endif
SetBit(parsed_cmdline_options, CMDLINE_COPYOVER);
}
else if (!str_cmp(argv[i], "--relvl") || !str_cmp(argv[i], "-r"))
{
int oldlev, newlev;
i++;
if (NullStr(argv[i]) || !is_number(argv[i])
|| (oldlev = atoi(argv[i])) <= 0)
{
logf("Usage: %s %s [old max level] [new max level]", argv[0],
argv[i]);
return false;
}
i++;
if (NullStr(argv[i]) || !is_number(argv[i])
|| (newlev = atoi(argv[i])) <= 0)
{
logf("Usage: %s %s [old max level] [new max level]", argv[0],
argv[i]);
return false;
}
boot_db();
set_game_levels(oldlev, newlev);
return false;
}
else if (!str_cmp("--createdirs", argv[i]))
{
if (create_directories())
{
log_string
("There may have been problems creating the directories...\n"
"create them manually then try again.");
}
else
{
log_string("Directory creation completed successfully...\n"
"Start the mud normally to continue.");
}
return false;
}
else if (!str_cmp(argv[i], "-h") || !str_cmp(argv[i], "--help"))
{
cmdline_help(argv);
return false;
}
else if (!IsSet(parsed_cmdline_options, CMDLINE_SET_PORT)
&& !NullStr(argv[i]) && is_number(argv[i]))
{
if ((parsed_mainport = atoi(argv[i])) <= 1024
|| parsed_mainport >= 65535)
{
log_string("Port number must be between 1024 and 65535.");
return false;
}
SetBit(parsed_cmdline_options, CMDLINE_SET_PORT);
}
else
{
logf("Invalid option '%s'...", argv[i]);
cmdline_help(argv);
return false;
}
}
return true;
}
int main(int argc, char **argv)
{
log_hold_till_commandline_options_parsed();
run_level = RUNLEVEL_INIT;
tzset();
boot_time = getcurrenttime();
#ifdef HAVE_GETUID
if (getuid() == 0)
{
log_string
("DO NOT RUN THE MUD AS ROOT!!! THIS IS A SECURITY RISK!!!");
exit(1);
}
#endif
if (!parse_cmdline_options(argc, argv))
{
mainport = parsed_mainport;
log_release_held_logs();
return 0;
}
if (check_directories(argv[0]))
{
log_release_held_logs();
exit(1);
}
mainport = parsed_mainport;
log_release_held_logs();
if ((fpReserve = fopen(NULL_FILE, "r")) == NULL)
{
log_error(NULL_FILE);
exit(1);
}
rw_mud_data(act_read);
SetBit(mud_info.cmdline_options, parsed_cmdline_options);
if (mainport == 0)
{
mainport = mud_info.default_port;
logf
("no mainport value specified on command line, using default value of %d",
mainport);
}
init_network();
init_globals(argv[0]);
#ifndef DISABLE_MYSQL
db_start();
#endif
logf("Starting up %s...", mud_info.name);
if (mud_control == INVALID_SOCKET)
{
if ((mud_control = init_socket(mainport)) == INVALID_SOCKET)
exit(1);
}
#ifndef DISABLE_WEBSRV
webport = mainport + mud_info.webport_offset;
if (!web_is_connected())
web_control = init_socket(webport);
#endif
#ifndef DISABLE_I3
I3_main(crs_info.status == CRS_COPYOVER);
#endif
boot_db();
set_signals();
logf("%s is ready to rock on %s, port %d.", mud_info.name, HOSTNAME,
mainport);
logf("Mud is running in the %s with a process id of %d",
IsSet(mud_info.cmdline_options,
CMDLINE_NO_BACKGROUND_PROCESS) ? "foreground" : "background",
getpid());
if (IsSet(mud_info.cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS)
&& !IsSet(mud_info.cmdline_options, CMDLINE_STARTUP_SCRIPT))
{
logf
("Pressing ctrl+c will terminate the mud process (unless you have copyovered)");
}
if (crs_info.status == CRS_COPYOVER)
copyover_recover();
game_loop(mud_control);
closesocket(mud_control);
log_string("Normal termination of game.");
exit(0);
return 0;
}
bool bind_ip(SOCKET fd, int port)
{
static struct sockaddr_in sa_zero;
struct sockaddr_in sa;
sa = sa_zero;
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
sa.sin_addr.s_addr = INADDR_ANY;
if (!NullStr(mud_info.bind_ip_address))
{
if (strlen(mud_info.bind_ip_address) < 7)
{
log_string("The 'bind_ip_address' line in " MUD_FILE
" is too short to be a valid ip address");
log_string("A valid example of bind_ip_address might read:");
log_string("bind_ip_address 127.0.0.1~");
log_string("Fix this using a text editor then restart the mud.");
return false;
}
if (strlen(mud_info.bind_ip_address) > 15)
{
log_string("The 'bind_ip_address' line in " MUD_FILE
" is missing a trailing ~ or is too long to be a valid ip address");
log_string("A valid example of bind_ip_address in might read:");
log_string("bind_ip_address 127.0.0.1~");
log_string("Fix this using a text editor then restart the mud.");
return false;
}
sa.sin_addr.s_addr = inet_addr(mud_info.bind_ip_address);
if (str_cmp(mud_info.bind_ip_address, "0.0.0.0"))
logf("Binding to '%s' as per bind_ip_address setting in "
MUD_FILE, mud_info.bind_ip_address);
}
if (bind(fd, (SOCKADDR *) & sa, sizeof(sa)) == SOCKET_ERROR)
{
socket_error("Init socket: bind");
if (NullStr(mud_info.bind_ip_address)
|| !str_cmp("0.0.0.0", mud_info.bind_ip_address))
{
if (!str_cmp("0.0.0.0", mud_info.bind_ip_address))
{
log_string
("NOTE: If you have to bind to a specific IP address (NOT port) "
"you can specify it in " MUD_FILE
" by changing the keyword " "bind_ip_address entry:");
log_string
("If this relates to you, you can achieve this by editing the "
MUD_FILE " file "
"and change the '0.0.0.0' in the line 'bind_ip_address 0.0.0.0~' to the "
"ip address your mud must listen on.");
log_string("e.g. 'bind_ip_address 127.0.0.1~'");
log_string
("The 127.0.0.1 example will make the mud listen for connections "
"only on 127.0.0.1 (localhost).");
}
else
{
log_string
("NOTE: If you have to bind to a specific IP address (NOT port) "
"you can specify it in " MUD_FILE
" by adding a bind_ip_address entry:");
log_string("e.g. add a line 'bind_ip_address 127.0.0.1~'");
}
}
else
{
logf
("NOTE: Mud attempted to bind to the specific IP Address '%s' as per the bind_ip_address "
"setting in " MUD_FILE
", remove that setting if appropriate.",
mud_info.bind_ip_address);
}
return false;
}
return true;
}
SOCKET init_socket(int port)
{
int x = 1;
SOCKET fd;
if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
socket_error("Init_socket: socket");
return INVALID_SOCKET;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *) &x, sizeof(x)) ==
SOCKET_ERROR)
{
socket_error("Init_socket: SO_REUSEADDR");
closesocket(fd);
return INVALID_SOCKET;
}
#if defined SO_DONTLINGER && !defined SYSV
{
struct linger ld;
ld.l_onoff = 1;
ld.l_linger = 1000;
if (setsockopt
(fd, SOL_SOCKET, SO_DONTLINGER, (char *) &ld,
sizeof(ld)) == SOCKET_ERROR)
{
socket_error("Init_socket: SO_DONTLINGER");
closesocket(fd);
return INVALID_SOCKET;
}
}
#endif
if (!bind_ip(fd, port))
{
closesocket(fd);
return INVALID_SOCKET;
}
if (listen(fd, 4) == SOCKET_ERROR)
{
socket_error("Init socket: listen");
closesocket(fd);
return INVALID_SOCKET;
}
return fd;
}
void show_greeting(Descriptor * dnew)
{
int num;
num = number_range(0, MAX_GREETING - 1);
if (help_greeting[num])
{
if (help_greeting[num][0] == '.')
d_print(dnew, help_greeting[num] + 1);
else
d_print(dnew, help_greeting[num]);
}
else
{
bugf("NULL Greeting! (%d)", num);
d_printlnf(dnew,
"\t{cWelcome to..." NEWLINE NEWLINE "\t\t{W%s" NEWLINE
NEWLINE "\t{cMay Your Stay Be.... {CMercenary{c!{x",
mud_info.name);
}
d_println(dnew,
"{c Original DikuMUD by Hans Staerfeldt, Katja Nyboe,"
NEWLINE
" Tom Madsen, Michael Seifert, and Sebastian Hammer"
NEWLINE
" Based on MERC 2.1 code by Hatchet, Furey, and Kahn"
NEWLINE " ROM 2.4 copyright (c) 1993-1998 Russ Taylor. "
NEWLINE
" 1stMud Server copyright (c) 2001-2004, Markanth.{x"
NEWLINE);
d_printf(dnew, "{c%s (type 'list' to use a name generator){x",
mud_info.login_prompt);
}
void game_loop(SOCKET ctrl)
{
struct timeval last_time;
#ifdef HAVE_SETITIMER
int vt_set = 0;
#endif
gettimeofday(&last_time, NULL);
current_time = (time_t) last_time.tv_sec;
run_level = RUNLEVEL_MAIN_LOOP;
while (run_level == RUNLEVEL_MAIN_LOOP)
{
fd_set in_set;
fd_set out_set;
fd_set exc_set;
Descriptor *d;
SOCKET maxdesc;
static struct timeval null_time;
struct timeval now_time;
long secDelta;
long usecDelta;
gettimeofday(&now_time, NULL);
usecDelta =
((int) last_time.tv_usec) - ((int) now_time.tv_usec) +
1000000 / PULSE_PER_SECOND;
secDelta = ((int) last_time.tv_sec) - ((int) now_time.tv_sec);
while (usecDelta < 0)
{
usecDelta += 1000000;
secDelta -= 1;
}
while (usecDelta >= 1000000)
{
usecDelta -= 1000000;
secDelta += 1;
}
if (secDelta > 0 || (secDelta == 0 && usecDelta > 0))
{
struct timeval stall_time;
stall_time.tv_usec = usecDelta;
stall_time.tv_sec = secDelta;
#ifdef WIN32
Sleep((stall_time.tv_sec * 1000) | (stall_time.tv_usec / 1000));
#else
if (select(0, NULL, NULL, NULL, &stall_time) == SOCKET_ERROR)
{
socket_error("Game_loop: select: stall");
exit(1);
}
#endif
}
gettimeofday(&last_time, NULL);
current_time = (time_t) last_time.tv_sec;
FD_ZERO(&in_set);
FD_ZERO(&out_set);
FD_ZERO(&exc_set);
FD_SET(ctrl, &in_set);
maxdesc = ctrl;
for (d = descriptor_first; d; d = d->next)
{
maxdesc = Max(maxdesc, d->descriptor);
FD_SET(d->descriptor, &in_set);
FD_SET(d->descriptor, &out_set);
FD_SET(d->descriptor, &exc_set);
}
if (select(maxdesc + 1, &in_set, &out_set, &exc_set, &null_time) ==
SOCKET_ERROR)
{
if (!check_errno(EINTR))
{
socket_error("Game_loop: select: poll");
exit(1);
}
}
if (FD_ISSET(ctrl, &in_set))
init_descriptor(ctrl);
for (d = descriptor_first; d != NULL; d = d_next)
{
d_next = d->next;
if (FD_ISSET(d->descriptor, &exc_set))
{
FD_CLR(d->descriptor, &in_set);
FD_CLR(d->descriptor, &out_set);
if (d->character && d->connected == CON_PLAYING)
save_char_obj(d->character);
d->outtop = 0;
socket_error("game_loop: freaky folk found.");
close_socket(d);
}
if (d->connected < CON_PLAYING)
{
if ((current_time - d->connect_time) > 15 * MINUTE)
{
d->outtop = 0;
close_socket(d);
}
}
}
for (d = descriptor_first; d != NULL; d = d_next)
{
d_next = d->next;
d->fcommand = false;
if (FD_ISSET(d->descriptor, &in_set))
{
if (d->character != NULL)
d->character->timer = 0;
if (!read_from_descriptor(d))
{
FD_CLR(d->descriptor, &out_set);
if (d->character != NULL && d->connected == CON_PLAYING)
save_char_obj(d->character);
d->outtop = 0;
close_socket(d);
socket_error("game_loop: unable to read_from_descriptor");
continue;
}
}
if (d->character != NULL && d->character->daze > 0)
--d->character->daze;
if (d->character != NULL && d->character->wait > 0)
{
--d->character->wait;
continue;
}
read_from_buffer(d);
if (!NullStr(d->incomm))
{
d->fcommand = true;
stop_idling(d->character);
#ifdef HAVE_SETITIMER
vt_set = 0;
set_vtimer(-1);
#endif
if (d->character && d->character->color_prefix != COLORCODE)
{
color_convert_prefix(d->character->color_prefix,
d->incomm);
}
if (d->showstr_point)
show_string(d, d->incomm);
else if (d->pString)
string_add(d->character, d->incomm);
else
crash_info.status = CRASH_LIKELY;
strcpy(crash_info.logline, d->incomm);
crash_info.desc = d;
switch (d->connected)
{
case CON_PLAYING:
substitute_alias(d, d->incomm);
break;
default:
nanny(d, d->incomm);
break;
}
crash_info.status = CRASH_UNLIKELY;
d->incomm[0] = '\0';
}
}
#ifndef DISABLE_I3
I3_loop();
#endif
crash_info.status = CRASH_UPDATING;
update_handler();
#ifndef DISABLE_WEBSRV
update_web_server();
#endif
crash_info.status = CRASH_UNKNOWN;
for (d = descriptor_first; d != NULL; d = d_next)
{
d_next = d->next;
if ((d->fcommand || d->outtop > 0)
&& FD_ISSET(d->descriptor, &out_set))
{
if (!process_output(d, true))
{
if (d->character != NULL && d->connected == CON_PLAYING)
save_char_obj(d->character);
d->outtop = 0;
close_socket(d);
socket_error("game_loop: unable to process_output");
}
}
}
#ifdef HAVE_SETITIMER
if (++vt_set >= 35)
{
vt_set = 0;
set_vtimer(-1);
}
#endif
}
return;
}
#ifdef WIN32
const char *get_winsock_error_text(int errorcode)
{
static char result[MSL];
#define WEM_CASE(m) case m: pszMsg = #m ; break
const char *pszMsg;
int iError = 0;
if (errorcode != 0)
{
iError = errorcode;
}
else
{
iError = WSAGetLastError();
}
switch (iError)
{
WEM_CASE(WSABASEERR);
WEM_CASE(WSAEINTR);
WEM_CASE(WSAEBADF);
WEM_CASE(WSAEACCES);
WEM_CASE(WSAEFAULT);
WEM_CASE(WSAEINVAL);
WEM_CASE(WSAEMFILE);
WEM_CASE(WSAEWOULDBLOCK);
WEM_CASE(WSAEINPROGRESS);
WEM_CASE(WSAEALREADY);
WEM_CASE(WSAENOTSOCK);
WEM_CASE(WSAEDESTADDRREQ);
WEM_CASE(WSAEMSGSIZE);
WEM_CASE(WSAEPROTOTYPE);
WEM_CASE(WSAENOPROTOOPT);
WEM_CASE(WSAEPROTONOSUPPORT);
WEM_CASE(WSAESOCKTNOSUPPORT);
WEM_CASE(WSAEOPNOTSUPP);
WEM_CASE(WSAEPFNOSUPPORT);
WEM_CASE(WSAEAFNOSUPPORT);
WEM_CASE(WSAEADDRINUSE);
WEM_CASE(WSAEADDRNOTAVAIL);
WEM_CASE(WSAENETDOWN);
WEM_CASE(WSAENETUNREACH);
WEM_CASE(WSAENETRESET);
WEM_CASE(WSAECONNABORTED);
WEM_CASE(WSAECONNRESET);
WEM_CASE(WSAENOBUFS);
WEM_CASE(WSAEISCONN);
WEM_CASE(WSAENOTCONN);
WEM_CASE(WSAESHUTDOWN);
WEM_CASE(WSAETOOMANYREFS);
WEM_CASE(WSAETIMEDOUT);
WEM_CASE(WSAECONNREFUSED);
WEM_CASE(WSAELOOP);
WEM_CASE(WSAENAMETOOLONG);
WEM_CASE(WSAEHOSTDOWN);
WEM_CASE(WSAEHOSTUNREACH);
WEM_CASE(WSAENOTEMPTY);
WEM_CASE(WSAEPROCLIM);
WEM_CASE(WSAEUSERS);
WEM_CASE(WSAEDQUOT);
WEM_CASE(WSAESTALE);
WEM_CASE(WSAEREMOTE);
WEM_CASE(WSAEDISCON);
WEM_CASE(WSASYSNOTREADY);
WEM_CASE(WSAVERNOTSUPPORTED);
WEM_CASE(WSANOTINITIALISED);
WEM_CASE(WSAHOST_NOT_FOUND);
WEM_CASE(WSATRY_AGAIN);
WEM_CASE(WSANO_RECOVERY);
WEM_CASE(WSANO_DATA);
default:
pszMsg = NULL;
}
if (pszMsg)
{
sprintf(result, "%s(%d)", pszMsg, iError);
}
else
{
sprintf(result, "unknown winsock error value %d.", iError);
}
return result;
};
#endif
bool socket_cntl(SOCKET desc)
{
#ifdef WIN32
unsigned long blockmode = 1;
if (ioctlsocket(desc, FIONBIO, &blockmode) == SOCKET_ERROR)
{
socket_error("error setting new socket to nonblocking");
return false;
}
#else
#if !defined(FNDELAY)
#define FNDELAY O_NDELAY
#endif
if (fcntl(desc, F_SETFL, FNDELAY) == SOCKET_ERROR)
{
socket_error("fcntl() FNDELAY");
return false;
}
#endif
return true;
}
void init_descriptor(int ctrl)
{
Descriptor *dnew;
struct sockaddr_in sock;
struct hostent *from;
SOCKET desc;
socklen_t size;
size = sizeof(sock);
if (getsockname(ctrl, (SOCKADDR *) & sock, &size) == SOCKET_ERROR)
{
socket_error("init_descriptor: getsockname");
}
if ((desc = accept(ctrl, (SOCKADDR *) & sock, &size)) == INVALID_SOCKET)
{
socket_error("New_descriptor: accept");
return;
}
if (!socket_cntl(desc))
{
socket_error("New_descriptor: cannot set desc to nonblocking");
return;
}
dnew = new_descriptor();
dnew->descriptor = desc;
dnew->connect_time = getcurrenttime();
size = sizeof(sock);
if (getpeername(desc, (SOCKADDR *) & sock, &size) == SOCKET_ERROR)
{
socket_error("New_descriptor: getpeername");
dnew->host = str_dup("(unknown)");
}
else
{
dnew->port = ntohs(sock.sin_port);
replace_str(&dnew->host, inet_ntoa(sock.sin_addr));
dnew->ip = ntohl(sock.sin_addr.s_addr);
logf("Sock.sinaddr: %s", dnew->host);
if (!IsSet(mud_info.mud_flags, NO_DNS_LOOKUPS))
{
if (
(from =
gethostbyaddr((char *) &sock.sin_addr, sizeof(sock.sin_addr),
AF_INET)) != NULL)
replace_str(&dnew->host, from->h_name);
}
}
if (check_ban(dnew->host, BAN_ALL))
{
d_write(dnew, "Your site has been banned from this mud." NEWLINE, 0);
closesocket(desc);
free_descriptor(dnew);
return;
}
Link(dnew, descriptor, next, prev);
init_telnet(dnew);
d_println(dnew, "Autodetecting IMP...v1.30");
d_println(dnew, "This world is Pueblo 1.10 enhanced.");
d_println(dnew,
"Welcome, would you like ANSI color? (Y)es, (N)o, (T)est:");
mud_info.stats.connections++;
mud_info.stats.boot_connects++;
return;
}
void close_socket(Descriptor * dclose)
{
CharData *ch;
if (dclose->outtop > 0)
process_output(dclose, false);
if (dclose->snoop_by != NULL)
{
d_println(dclose->snoop_by, "Your victim has left the game.");
}
{
Descriptor *d;
for (d = descriptor_first; d != NULL; d = d->next)
{
if (d->snoop_by == dclose)
d->snoop_by = NULL;
}
}
if ((ch = CH(dclose)) != NULL)
{
logf("Closing link to %s.", ch->name);
if (
(dclose->connected == CON_PLAYING
&& run_level != RUNLEVEL_SHUTDOWN)
|| ((dclose->connected >= CON_NOTE_TO)
&& (dclose->connected <= CON_NOTE_FINISH)))
{
extract_quest(ch);
extract_war(ch);
extract_arena(ch);
act("$n has lost $s link.", ch, NULL, NULL, TO_ROOM);
wiznet("Net death has claimed $N.", ch, NULL, WIZ_LINKS, 0, 0);
ch->desc = NULL;
}
else
{
free_char(ch);
}
}
free_runbuf(dclose);
if (d_next == dclose)
d_next = d_next->next;
UnLink(dclose, descriptor, next, prev);
#ifndef DISABLE_MCCP
if (dclose->out_compress)
{
deflateEnd(dclose->out_compress);
free_mem(dclose->out_compress_buf);
free_mem(dclose->out_compress);
}
#endif
closesocket(dclose->descriptor);
free_descriptor(dclose);
return;
}
void read_from_buffer(Descriptor * d)
{
int i, j, k;
if (!NullStr(d->incomm))
return;
if (d->character && d->character->position == POS_FIGHTING && d->run_buf)
free_runbuf(d);
if (d->run_buf)
{
while (isdigit(*d->run_head) && *d->run_head != '\0')
{
char *s;
char *e;
s = (char *) d->run_head;
while (isdigit(*s))
s++;
e = s;
while (*(--s) == '0' && s != d->run_head)
;
if (isdigit(*s) && *s != '0' && *e != 'o')
{
d->incomm[0] = *e;
d->incomm[1] = '\0';
s[0]--;
while (isdigit(*(++s)))
*s = '9';
return;
}
if (*e == 'o')
d->run_head = e;
else
d->run_head = ++e;
}
if (*d->run_head != '\0')
{
if (*d->run_head != 'o')
{
d->incomm[0] = *d->run_head++;
d->incomm[1] = '\0';
return;
}
else
{
char buf[MAX_INPUT_LENGTH];
d->run_head++;
strcpy(buf, "open ");
switch (*d->run_head)
{
case 'n':
strcat(buf, "north");
break;
case 's':
strcat(buf, "south");
break;
case 'e':
strcat(buf, "east");
break;
case 'w':
strcat(buf, "west");
break;
case 'u':
strcat(buf, "up");
break;
case 'd':
strcat(buf, "down");
break;
default:
return;
}
strcpy(d->incomm, buf);
d->run_head++;
return;
}
}
free_runbuf(d);
}
for (i = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++)
{
if (d->inbuf[i] == '\0')
return;
}
for (i = 0, k = 0; d->inbuf[i] != '\n' && d->inbuf[i] != '\r'; i++)
{
if (k >= MAX_INPUT_LENGTH - 32)
{
d_write(d, "Line too long." NEWLINE, 0);
for (; d->inbuf[i] != '\0'; i++)
{
if (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
break;
}
d->inbuf[i] = '\n';
d->inbuf[i + 1] = '\0';
break;
}
if (d->inbuf[i] == '\b' && k > 0)
--k;
else if (MudFlag(DISABLE_EXTENDED_ASCII_CHARS))
{
if (isascii(d->inbuf[i]) && isprint(d->inbuf[i]))
d->incomm[k++] = d->inbuf[i];
}
else
{
unsigned char c = d->inbuf[i];
if (c > 0x1F && c != 0x7F && c != 0xFF) // accept anything but control characters
{
d->incomm[k++] = d->inbuf[i];
}
}
}
if (k == 0)
d->incomm[k++] = ' ';
d->incomm[k] = '\0';
if (k > 1 || d->incomm[0] == '!')
{
if (d->incomm[0] != '!' && str_cmp(d->incomm, d->inlast))
{
d->repeat = 0;
}
else
{
if (++d->repeat >= 25 && d->character
&& d->connected == CON_PLAYING)
{
logf("%s input spamming!", d->host);
new_wiznet(d->character, NULL, WIZ_SPAM, false,
get_trust(d->character),
"Spam spam spam $N spam spam spam spam spam! (%s)",
d->incomm[0] == '!' ? d->inlast : d->incomm);
d->repeat = 0;
}
}
}
if (d->incomm[0] == '!')
strcpy(d->incomm, d->inlast);
else
strcpy(d->inlast, d->incomm);
while (d->inbuf[i] == '\n' || d->inbuf[i] == '\r')
i++;
for (j = 0; (d->inbuf[j] = d->inbuf[i + j]) != '\0'; j++)
;
return;
}
#include "descriptor.h"
#include "character.h"
#define CAN_SHOW_PROMPT ((!IsNPC(ch) && IsSet(ch->act, PLR_AUTOPROMPT)) \
|| (d->fcommand && !d->run_buf) || ch->fighting)
#include "comm_prompt.h"
bool process_output(Descriptor * d, bool fPrompt)
{
if (run_level != RUNLEVEL_SHUTDOWN)
{
CharData *ch = d->character;
d->fPrompt = false;
if (d->showstr_point)
{
const char *ptr;
size_t shown_lines = 0, total_lines = 0;
for (ptr = d->showstr_head; ptr != d->showstr_point; ptr++)
if (*ptr == '\n')
shown_lines++;
total_lines = shown_lines + line_count(d->showstr_point);
d_printf(d,
NEWLINE "(%d%%) Please type " MXPTAG("Pager")
"(H)elp, (R)efresh, (B)ack, or (C)ontinue or hit ENTER"
MXPTAG("/Pager") ".", Percent(shown_lines, total_lines));
d->fPrompt = true;
}
else if (fPrompt)
{
switch (d->connected)
{
case CON_NOTE_TEXT:
d_print(d, "> ");
d->fPrompt = true;
break;
case CON_PLAYING:
if (d->pString)
{
d_print(d, "> ");
d->fPrompt = true;
}
else if (ch)
{
CharData *victim;
if ((victim = ch->fighting) != NULL
&& can_see(ch, victim))
{
int percent;
char wound[100];
if (victim->max_hit > 0)
percent = victim->hit * 100 / victim->max_hit;
else
percent = -1;
if (percent >= 100)
sprintf(wound, "is in excellent condition.");
else if (percent >= 90)
sprintf(wound, "has a few scratches.");
else if (percent >= 75)
sprintf(wound,
"has some small wounds and bruises.");
else if (percent >= 50)
sprintf(wound, "has quite a few wounds.");
else if (percent >= 30)
sprintf(wound,
"has some big nasty wounds and scratches.");
else if (percent >= 15)
sprintf(wound, "looks pretty hurt.");
else if (percent >= 0)
sprintf(wound, "is in awful condition.");
else
sprintf(wound, "is bleeding to death.");
d_printlnf(d, "%s %s", Upper(GetName(victim)),
wound);
}
ch = CH(d);
if (!IsSet(ch->comm, COMM_COMPACT)
&& (CAN_SHOW_PROMPT || d->editor != ED_NONE))
{
d_println(d, NULL);
}
if (IsSet(ch->comm, COMM_GPROMPT) && CAN_SHOW_PROMPT)
{
bust_a_group_prompt(d->character);
d->fPrompt = true;
}
if (IsSet(ch->comm, COMM_PROMPT))
{
if (CAN_SHOW_PROMPT)
{
bust_a_prompt(d->character);
d->fPrompt = true;
}
else if (d->editor != ED_NONE)
{
d_printf(d, "{cOLC %s : {W%s{x",
olc_ed_name(d), olc_ed_vnum(d));
d->fPrompt = true;
}
}
if (IsSet(ch->comm, COMM_TELNET_GA))
{
d_write(d, go_ahead_str, 0);
}
else if (IsSet(ch->comm, COMM_TELNET_EOR))
{
const char eor_str[] = {
IAC, EOR, NUL
};
d_write(d, eor_str, 0);
d->fPrompt = false;
}
}
break;
default:
d->fPrompt = true;
break;
}
}
}
if (d->outtop == 0)
return true;
if (d->snoop_by != NULL)
{
if (d->character != NULL)
d_print(d->snoop_by, d->character->name);
d_print(d->snoop_by, "> ");
print_stripped_client_code(d->snoop_by, d->outbuf, d->outtop);
}
return convert_color_mxp_tags(d);
}
bool check_parse_name(const char *name)
{
ClanData *clan;
if (is_exact_name
(name, "all auto immortal self someone something the you loner none"))
{
return false;
}
for (clan = clan_first; clan; clan = clan->next)
{
if (tolower(name[0]) == tolower(clan->name[0])
&& !str_cmp(name, clan->name))
return false;
}
if (str_cmp(capitalize(name), "Alander")
&& (!str_prefix("Alan", name) || !str_suffix("Alander", name)))
return false;
if (strlen(name) < 2)
return false;
if (strlen(name) > 12)
return false;
{
const char *pc;
bool fIll, adjcaps = false, cleancaps = false;
unsigned int total_caps = 0;
fIll = true;
for (pc = name; *pc != '\0'; pc++)
{
if (!isalpha(*pc))
return false;
if (isupper(*pc))
{
if (adjcaps)
cleancaps = true;
total_caps++;
adjcaps = true;
}
else
adjcaps = false;
if (tolower(*pc) != 'i' && tolower(*pc) != 'l')
fIll = false;
}
if (fIll)
return false;
if (cleancaps
|| (total_caps > (strlen(name)) / 2 && strlen(name) < 3))
return false;
}
{
CharIndex *pMobIndex;
int iHash;
for (iHash = 0; iHash < MAX_KEY_HASH; iHash++)
{
for (pMobIndex = char_index_hash[iHash]; pMobIndex != NULL;
pMobIndex = pMobIndex->next)
{
if (is_name(name, pMobIndex->player_name))
return false;
}
}
}
return true;
}
bool check_reconnect(Descriptor * d, const char *name, bool fConn)
{
CharData *ch;
for (ch = char_first; ch != NULL; ch = ch->next)
{
if (!IsNPC(ch) && (!fConn || ch->desc == NULL)
&& !str_cmp(d->character->name, ch->name))
{
if (fConn == false)
{
replace_str(&d->character->pcdata->pwd, ch->pcdata->pwd);
}
else
{
free_char(d->character);
d->character = ch;
ch->desc = d;
ch->timer = 0;
chprintlnf(ch,
"{cReconnecting%s{x" NEWLINE "Welcome back %s.",
colorize("....."), ch->name);
if (!IsNPC(ch) && ch->pcdata->tells)
{
chprintlnf(ch,
"You have %d tells waiting. Type '%s' to view them.",
ch->pcdata->tells, cmd_name(do_replay));
}
act("$n has reconnected.", ch, NULL, NULL, TO_ROOM);
logf("%s@%s reconnected.", ch->name, d->host);
wiznet("$N groks the fullness of $S link.", ch, NULL,
WIZ_LINKS, false, 0);
d->connected = CON_PLAYING;
do_function(ch, &do_ncheck, "");
}
return true;
}
}
return false;
}
bool check_playing(Descriptor * d, const char *name)
{
Descriptor *dold;
for (dold = descriptor_first; dold; dold = dold->next)
{
if (dold != d && dold->character != NULL
&& dold->connected != CON_GET_NAME
&& dold->connected != CON_GET_OLD_PASSWORD
&& !str_cmp(name, CH(dold)->name))
{
d_println(d, "{cThat character is already playing.{x");
d_print(d, "{cDo you wish to connect anyway ({WY{c/{WN{c?{x");
d->connected = CON_BREAK_CONNECT;
return true;
}
}
return false;
}
void stop_idling(CharData * ch)
{
if (ch == NULL || ch->desc == NULL || ch->desc->connected != CON_PLAYING
|| ch->was_in_room == NULL
|| ch->in_room != get_room_index(ROOM_VNUM_LIMBO))
return;
ch->timer = 0;
char_from_room(ch);
char_to_room(ch, ch->was_in_room);
ch->was_in_room = NULL;
act("$n has returned from the void.", ch, NULL, NULL, TO_ROOM);
return;
}
void sendpage(CharData * ch, const char *txt)
{
Descriptor *d;
if (NullStr(txt) || (d = ch->desc) == NULL)
return;
if (ch->lines <= 0)
{
d_print(d, txt);
return;
}
if (!NullStr(d->showstr_head))
{
char *fub;
size_t i, size_new = strlen(txt) + strlen(d->showstr_head) + 2;
alloc_mem(fub, char, size_new);
fub[0] = '\0';
strncat(fub, d->showstr_head, size_new);
i = strlen(fub) - strlen(d->showstr_point);
strncat(fub, txt, size_new);
replace_str(&d->showstr_head, fub);
d->showstr_point = d->showstr_head + i;
free_mem(fub);
return;
}
replace_str(&d->showstr_head, txt);
d->showstr_point = d->showstr_head;
show_string(d, "");
return;
}
void show_string(Descriptor * d, char *input)
{
char buffer[MAX_STRING_LENGTH * 3];
char buf[MAX_INPUT_LENGTH];
register const char *scan;
register char *scan2;
register const char *chk;
int lines = 0;
int maxlines = get_scr_lines(d->character);
int toggle = 1;
one_argument(input, buf);
switch (toupper(buf[0]))
{
case '\0':
case 'C':
lines = 0;
break;
case 'R':
lines = -1 - maxlines;
break;
case 'B':
lines = -(2 * maxlines);
break;
case '?':
case 'H':
d_println(d,
"Pager help:" NEWLINE "C or Enter next page" NEWLINE
"R refresh this page");
d_println(d,
"B previous page" NEWLINE
"H or ? help" NEWLINE "Any other keys exit.");
return;
default:
if (d->showstr_head)
{
replace_str(&d->showstr_head, "");
}
d->showstr_point = NULL;
return;
}
if (lines < 0)
{
for (scan = d->showstr_point; scan > d->showstr_head; scan--)
if ((*scan == '\n') || (*scan == '\r'))
{
toggle = -toggle;
if (toggle < 0)
if (!(++lines))
break;
}
d->showstr_point = scan;
}
lines = 0;
toggle = 1;
for (scan2 = buffer;; scan2++, d->showstr_point++)
if (((*scan2 = *d->showstr_point) == '\n' || *scan2 == '\r')
&& (toggle = -toggle) < 0)
lines++;
else if (!*scan2
|| (d->character && !IsNPC(d->character)
&& lines >= maxlines))
{
*scan2 = '\0';
d_print(d, buffer);
for (chk = d->showstr_point; isspace(*chk); chk++)
;
if (!*chk)
{
if (d->showstr_head)
{
replace_str(&d->showstr_head, "");
}
d->showstr_point = 0;
}
return;
}
return;
}
char *fname(const char *namelist)
{
static char holder[256];
char *point;
for (point = holder; isalpha(*namelist); namelist++, point++)
*point = *namelist;
*point = '\0';
return (holder);
}
void perform_act(const char *orig, CharData * ch, const void *arg1,
const void *arg2, flag_t type, CharData * to)
{
CharData *vch = (CharData *) arg2;
ObjData *obj1 = (ObjData *) arg1;
ObjData *obj2 = (ObjData *) arg2;
char buf[MSL * 5];
register const char *str, *i = NULL;
register char *point;
size_t z;
point = buf;
if (IsSet(type, TO_SOCIALS))
add_text(CTAG(_SOCIALS), point);
for (str = orig; *str != '\0'; str++)
{
if (*str != '$')
{
*point++ = *str;
continue;
}
str++;
i = "<@@@>";
if (!arg2 && isupper(*str))
{
logf("perform_act:missing arg2 for code %c.", *str);
i = " <@@@> ";
}
else
{
switch (*str)
{
default:
logf("perform_act:bad code %c.", *str);
i = " <@@@> ";
break;
case '$':
i = "$";
break;
case 't':
if (arg1)
{
if (IsSet(type, TO_DAMAGE)
&& (IsNPC(to) || !IsSet(to->act, PLR_AUTODAMAGE)))
i = "";
else
i = (const char *) arg1;
}
else
log_string("perform_act:bad code $t for 'arg1'");
break;
case 'T':
if (arg2)
i = (const char *) arg2;
else
log_string("perform_act:bad code $T for 'arg2'");
break;
case 'n':
if (ch && to)
i = Pers(ch, to);
else
log_string
("perform_act:bad code $n for 'ch' or 'to'");
break;
case 'N':
if (vch && to)
i = Pers(vch, to);
else
log_string
("perform_act:bad code $N for 'ch' or 'to'");
break;
case 'e':
if (ch)
i = he_she[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $e for 'ch'");
break;
case 'E':
if (vch)
i = he_she[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $E for 'vch'");
break;
case 'm':
if (ch)
i = him_her[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $m for 'ch'");
break;
case 'M':
if (vch)
i = him_her[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $M for 'vch'");
break;
case 's':
if (ch)
i = his_her[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $s for 'ch'");
break;
case 'S':
if (vch)
i = his_her[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $S for 'vch'");
break;
case 'g':
if (ch && ch->deity != NULL)
i = ch->deity->name;
else
log_string("perform_act:bad code $g for 'ch'");
break;
case 'G':
if (vch && vch->deity != NULL)
i = vch->deity->name;
else
log_string("perform_act:bad code $G for 'vch'");
break;
case 'c':
if (ch && is_clan(ch))
i = CharClan(ch)->name;
else
log_string("perform_act:bad code $c for 'ch'");
break;
case 'C':
if (vch && is_clan(vch))
i = CharClan(vch)->name;
else
log_string("perform_act:bad code $C for 'vch'");
break;
case 'o':
if (to && obj1)
i =
can_see_obj(to,
obj1) ? fname(obj1->name) :
"something";
else
log_string
("perform_act:bad code $o for 'to' and 'obj1'");
break;
case 'O':
if (to && obj2)
i =
can_see_obj(to,
obj2) ? fname(obj2->name) :
"something";
else
log_string
("perform_act:bad code $O for 'to' and 'obj2'");
break;
case 'p':
if (to && obj1)
i =
can_see_obj(to,
obj1) ? obj1->short_descr :
"something";
else
log_string
("perform_act:bad code $p for 'to' and 'obj1'");
break;
case 'P':
if (to && obj2)
i =
can_see_obj(to,
obj2) ? obj2->short_descr :
"something";
else
log_string
("perform_act:bad code $P for 'to' and 'obj2'");
break;
case 'd':
if (arg2 == NULL || ((const char *) arg2)[0] == '\0')
{
i = "door";
}
else
{
char name[MIL];
one_argument((const char *) arg2, name);
i = name;
}
break;
}
}
while ((*point = *i) != '\0')
point++, i++;
}
*point++ = '{';
*point++ = 'x';
*point++ = '\n';
*point++ = '\r';
*point = '\0';
z = skipcol(buf);
buf[z] = toupper(buf[z]);
if (to->desc)
{
if (to->desc->connected == CON_PLAYING)
d_print(to->desc, buf);
}
else if (IsNPC(to) && MOBtrigger && HasTriggerMob(to, TRIG_ACT))
p_act_trigger(buf, to, NULL, NULL, ch, arg1, arg2, TRIG_ACT);
if (ch && ch->in_room && IsSet(type, TO_ROOM | TO_NOTVICT))
{
ObjData *obj, *obj_next;
CharData *tch, *tch_next;
for (obj = ch->in_room->content_first; obj; obj = obj_next)
{
obj_next = obj->next_content;
if (HasTriggerObj(obj, TRIG_ACT))
p_act_trigger(orig, NULL, obj, NULL, ch, NULL, NULL,
TRIG_ACT);
}
for (tch = ch; tch; tch = tch_next)
{
tch_next = tch->next_in_room;
for (obj = tch->carrying_first; obj; obj = obj_next)
{
obj_next = obj->next_content;
if (HasTriggerObj(obj, TRIG_ACT))
p_act_trigger(orig, NULL, obj, NULL, ch, NULL, NULL,
TRIG_ACT);
}
}
if (HasTriggerRoom(ch->in_room, TRIG_ACT))
p_act_trigger(orig, NULL, NULL, ch->in_room, ch, NULL, NULL,
TRIG_ACT);
}
return;
}
const char *perform_act_string(const char *orig, CharData * ch,
const void *arg1, const void *arg2,
bool cReturn)
{
CharData *vch = (CharData *) arg2;
ObjData *obj1 = (ObjData *) arg1;
ObjData *obj2 = (ObjData *) arg2;
char buf[MSL * 5];
register const char *str, *i = NULL;
register char *point;
for (str = orig, point = buf; *str != '\0'; str++)
{
if (*str != '$')
{
*point++ = *str;
continue;
}
str++;
i = "<@@@>";
if (!arg2 && isupper(*str))
{
logf("perform_act:missing arg2 for code %c.", *str);
i = " <@@@> ";
}
else
{
switch (*str)
{
default:
logf("perform_act:bad code %c.", *str);
i = " <@@@> ";
break;
case '$':
i = "$";
break;
case 't':
if (arg1)
{
i = (const char *) arg1;
}
else
log_string("perform_act:bad code $t for 'arg1'");
break;
case 'T':
if (arg2)
i = (const char *) arg2;
else
log_string("perform_act:bad code $T for 'arg2'");
break;
case 'n':
if (ch)
i = IsNPC(ch) ? ch->short_descr : ch->name;
else
log_string("perform_act:bad code $n for 'ch'");
break;
case 'N':
if (vch)
i = IsNPC(vch) ? vch->short_descr : vch->name;
else
log_string("perform_act:bad code $N for 'vch'");
break;
case 'e':
if (ch)
i = he_she[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $e for 'ch'");
break;
case 'E':
if (vch)
i = he_she[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $E for 'vch'");
break;
case 'm':
if (ch)
i = him_her[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $m for 'ch'");
break;
case 'M':
if (vch)
i = him_her[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $M for 'vch'");
break;
case 's':
if (ch)
i = his_her[Range(0, ch->sex, 2)];
else
log_string("perform_act:bad code $s for 'ch'");
break;
case 'S':
if (vch)
i = his_her[Range(0, vch->sex, 2)];
else
log_string("perform_act:bad code $S for 'vch'");
break;
case 'g':
if (ch && ch->deity != NULL)
i = ch->deity->name;
else
log_string("perform_act:bad code $g for 'ch'");
break;
case 'G':
if (vch && vch->deity != NULL)
i = vch->deity->name;
else
log_string("perform_act:bad code $G for 'vch'");
break;
case 'c':
if (ch && is_clan(ch))
i = CharClan(ch)->name;
else
log_string("perform_act:bad code $c for 'ch'");
break;
case 'C':
if (vch && is_clan(vch))
i = CharClan(vch)->name;
else
log_string("perform_act:bad code $C for 'vch'");
break;
case 'o':
if (obj1)
i = fname(obj1->name);
else
log_string
("perform_act:bad code $o for 'to' and 'obj1'");
break;
case 'O':
if (obj2)
i = fname(obj2->name);
else
log_string("perform_act:bad code $O for 'obj2'");
break;
case 'p':
if (obj1)
i = obj1->short_descr;
else
log_string("perform_act:bad code $p for 'obj1'");
break;
case 'P':
if (obj2)
i = obj2->short_descr;
else
log_string("perform_act:bad code $P for 'obj2'");
break;
case 'd':
if (arg2 == NULL || ((const char *) arg2)[0] == '\0')
{
i = "door";
}
else
{
char name[MIL];
one_argument((const char *) arg2, name);
i = name;
}
break;
}
}
while ((*point = *i) != '\0')
point++, i++;
}
*point++ = '{';
*point++ = 'x';
if (cReturn)
{
*point++ = '\n';
*point++ = '\r';
}
*point = '\0';
return Upper(buf);
}
#define SENDOK(ch, type) ((IsNPC(ch) || ((ch)->desc && (ch->desc->connected == CON_PLAYING))) \
&& (ch)->position >= min_pos)
void act_new(const char *format, CharData * ch, const void *arg1,
const void *arg2, flag_t type, position_t min_pos)
{
Descriptor *d;
RoomIndex *room;
CharData *to = (CharData *) arg2;
if (NullStr(format))
return;
if (IsSet(type, TO_CHAR))
{
if (ch && SENDOK(ch, type))
perform_act(format, ch, arg1, arg2, type, ch);
}
if (IsSet(type, TO_VICT))
{
if (to && SENDOK(to, type) && to != ch)
perform_act(format, ch, arg1, arg2, type, to);
}
if (IsSet(type, TO_ZONE | TO_ALL))
{
for (d = descriptor_first; d; d = d->next)
{
CharData *vch = CH(d);
if (vch && SENDOK(vch, type) && (vch != ch)
&&
((IsSet
(type, TO_ALL) || (vch->in_room
&& vch->in_room->area ==
ch->in_room->area))))
perform_act(format, ch, arg1, arg2, type, vch);
}
}
if (IsSet(type, TO_ROOM | TO_NOTVICT))
{
ObjData *obj1 = (ObjData *) arg1;
ObjData *obj2 = (ObjData *) arg2;
if (ch && ch->in_room != NULL)
room = ch->in_room;
else if (obj1 && obj1->in_room != NULL)
room = obj1->in_room;
else if (obj2 && obj2->in_room != NULL)
room = obj2->in_room;
else
{
bugf("no valid target '%s'", format);
return;
}
for (to = room->person_first; to; to = to->next_in_room)
{
if (SENDOK(to, type) && (to != ch)
&& (IsSet(type, TO_ROOM) || (to != (CharData *) arg2)))
perform_act(format, ch, arg1, arg2, type, to);
}
}
return;
}
void bugf(const char *fmt, ...)
{
char buf[2 * MSL];
va_list args;
if (NullStr(fmt))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
bug(buf);
}
void logf(const char *fmt, ...)
{
char buf[2 * MSL];
va_list args;
if (NullStr(fmt))
return;
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
log_string(buf);
}
void set_game_levels(int Old, int New)
{
CmdData *cmd;
HelpData *pHelp;
ObjIndex *pObj;
CharIndex *pMob;
BanData *ban;
DisabledData *d;
ClanMember *mbr;
WebpassData *wpass;
int hash, sn, x;
int diff = MAX_LEVEL - LEVEL_IMMORTAL;
int imm_level = Old - diff;
int mod = New - Old;
logf("Old Imm Level = %d, Old Max Level = %d.", imm_level, Old);
logf("New Imm Level = %d, New Max Level = %d.", New - diff, New);
for (cmd = cmd_first; cmd; cmd = cmd->next)
{
if (cmd->level >= imm_level)
cmd->level += mod;
}
rw_cmd_data(act_write);
for (pHelp = help_first; pHelp; pHelp = pHelp->next)
{
if (pHelp->level >= imm_level)
pHelp->level += mod;
}
rw_help_data(act_write);
for (hash = 0; hash < MAX_KEY_HASH; hash++)
{
for (pMob = char_index_hash[hash]; pMob; pMob = pMob->next)
{
if (pMob->level >= imm_level)
{
pMob->level += mod;
TouchArea(pMob->area);
}
}
for (pObj = obj_index_hash[hash]; pObj; pObj = pObj->next)
{
AffectData *paf;
if (pObj->level >= imm_level)
{
pObj->level += mod;
TouchArea(pObj->area);
}
switch (pObj->item_type)
{
case ITEM_POTION:
case ITEM_SCROLL:
case ITEM_PILL:
case ITEM_WAND:
case ITEM_STAFF:
if (pObj->value[0] >= imm_level)
{
pObj->value[0] += mod;
TouchArea(pObj->area);
}
break;
default:
break;
}
for (paf = pObj->affect_first; paf; paf = paf->next)
{
if (paf->level >= imm_level)
{
paf->level += mod;
TouchArea(pObj->area);
}
}
}
}
do_function(NULL, &do_asave, "changed");
for (ban = ban_first; ban; ban = ban->next)
{
if (ban->level >= imm_level)
ban->level += mod;
}
rw_ban_data(act_write);
for (d = disabled_first; d; d = d->next)
{
if (d->level >= imm_level)
d->level += mod;
}
rw_disabled_data(act_read);
for (sn = 0; sn < top_skill; sn++)
{
for (x = 0; x < top_class; x++)
{
if (skill_table[sn].skill_level[x] >= imm_level)
skill_table[sn].skill_level[x] += mod;
}
}
rw_skill_data(act_write);
for (mbr = mbr_first; mbr; mbr = mbr->next)
{
if (mbr->level >= imm_level)
mbr->level += mod;
}
rw_mbr_data(act_write);
for (wpass = wpwd_first; wpass; wpass = wpass->next)
{
if (wpass->level >= imm_level)
wpass->level += mod;
}
rw_wpwd_data(act_write);
}
const char *print_ip(unsigned long ip)
{
struct sockaddr_in sock;
static char buf[5][100];
static int i;
i++;
i %= 5;
sock.sin_addr.s_addr = ip;
strcpy(buf[i], inet_ntoa(sock.sin_addr));
return buf[i];
}
size_t line_count(const char *s)
{
size_t count = 0;
for (; *s; s++)
if (*s == '\n')
count++;
return count;
}
int col_print(Column * c, const char *txt)
{
switch (c->type)
{
case COLS_BUF:
return bprint((Buffer *) c->to, txt);
case COLS_CHAR:
return chprint((CharData *) c->to, txt);
case COLS_DESC:
return d_print((Descriptor *) c->to, txt);
default:
bugf("void_print: invalid type");
return 0;
}
}
int print_cols(Column * c, const char *format, ...)
{
int out = 0;
size_t buf_len = 0;
bool has_nl = false;
if (!c)
return 0;
if (!NullStr(format))
{
va_list args;
char buf[MPL];
va_start(args, format);
vsnprintf(buf, sizeof(buf), format, args);
va_end(args);
buf_len = cstrlen(buf);
c->line_pos += buf_len;
if (c->line_pos >= c->line_len)
{
if (!c->newline)
out += col_print(c, NEWLINE);
c->col_pos = 0;
c->newline = true;
c->line_pos = buf_len;
}
has_nl = has_newline(buf);
out += col_print(c, buf);
}
if (has_nl)
{
c->newline = true;
c->col_pos = c->line_pos = 0;
}
else if (++c->col_pos >= c->columns)
{
if (!c->newline)
col_print(c, NEWLINE);
c->newline = true;
c->col_pos = c->line_pos = 0;
}
else
{
int col_diff = 0;
if (c->col_len > buf_len)
{
col_diff = c->col_len - buf_len;
}
else if (buf_len > c->col_len)
{
int diff_count = 0;
while (buf_len > c->col_len)
{
++diff_count;
buf_len -= c->col_len;
}
col_diff = (c->col_len * diff_count) - buf_len;
c->col_pos += diff_count;
}
if (col_diff > 0)
{
c->line_pos += col_diff;
out += col_print(c, FORMATF("%*s", col_diff, " "));
}
c->newline = false;
}
return out;
}
bool cols_nl(Column * c)
{
if (!c)
return false;
if (!c->newline)
{
col_print(c, NEWLINE);
c->newline = true;
c->line_pos = 0;
c->col_pos = 0;
return true;
}
return false;
}
void set_cols(Column * c, CharData * ch, int columns, column_t type, void *to)
{
if (!c)
return;
c->newline = false;
c->line_len = get_scr_cols(ch);
c->col_pos = 0;
c->line_pos = 0;
c->columns = columns;
c->type = type;
c->to = to;
c->col_len = c->line_len / c->columns;
}
int cols_header(Column * c, const char *format, ...)
{
size_t i;
int out;
char head[MPL];
va_list args;
if (NullStr(format) || !c)
return 0;
va_start(args, format);
vsnprintf(head, sizeof(head), format, args);
va_end(args);
for (i = out = 0; i < c->columns && !c->newline; i++)
out += print_cols(c, head);
return out;
}