/************************************************************************** * 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; }