/************************************************************************** * 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)); #ifdef WIN32 void gettimeofday (struct timeval *t, void *tz) { struct timeb timebuffer; ftime (&timebuffer); t->tv_sec = timebuffer.time; t->tv_usec = timebuffer.millitm * 1000; } #endif 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 = SOCKET_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) { if (gethostname (HOSTNAME, sizeof (HOSTNAME)) == -1 || NullStr (HOSTNAME)) strcpy (HOSTNAME, "localhost"); if (!getcwd (CWDIR, sizeof (CWDIR)) || NullStr (CWDIR)) strcpy (CWDIR, AREA_DIR); #if defined WIN32 || defined __CYGWIN__ do { char *p, sym[2] = DIR_SYM; if ((p = strrchr (exename, sym[0])) != NULL) { p++; strcpy (exename, p); } if (str_suffix (".exe", exename)) strcat (exename, ".exe"); #ifdef NOT_WINDOWS_NT /* Use this part if your not using windows NT/XP */ do { struct stat chk; int i; if (!str_suffix ("2.exe", exename)) strcpy (EXE_FILE, str_rep (exename, "2.exe", ".exe")); else strcpy (EXE_FILE, str_rep (exename, ".exe", "2.exe")); if (stat (EXE_FILE, &chk) == -1) { char *shell = getenv ("ComSpec"); /* hopefully command.com ! */ if (shell) { system (FORMATF ("%s /c copy %s %s", shell, exename, EXE_FILE)); break; } } logf ("%s not found! Copyover unavailable!", EXE_FILE); } while (0); #endif } while (0); #endif strcpy (EXE_FILE, exename); 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 ("-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 "."); } bool parse_cmdline_options (int argc, char **argv) { int i; mainport = 0; parsed_mainport = 0; #ifdef WIN32 mud_info.cmdline_options = CMDLINE_NO_BACKGROUND_PROCESS | CMDLINE_LOG_CONSOLE; #else mud_info.cmdline_options = 0; #endif for (i = 1; i < argc; i++) { if (!str_cmp ("-q", argv[i]) || !str_cmp ("--quiet", argv[i])) { SetBit (mud_info.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 (mud_info.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 (mud_info.cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS); log_string ("Disabling daemon mode..."); } else if (!str_cmp (argv[i], "-nl") || !str_cmp (argv[i], "--nologfile")) { SetBit (mud_info.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 (mud_info.cmdline_options, CMDLINE_LOG_CONSOLE); log_string ("Logging to console..."); if (IsSet (mud_info.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 (mud_info.cmdline_options, CMDLINE_LOG_CONSOLE); log_string ("Logging to console disabled..."); } else if (!str_cmp ("-f", argv[i]) || !str_cmp ("--foreground", argv[i])) { SetBit (mud_info.cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS); SetBit (mud_info.cmdline_options, CMDLINE_LOG_CONSOLE); log_string ("Running mud in foreground..."); if (IsSet (mud_info.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 (mud_info.cmdline_options, CMDLINE_NO_BACKGROUND_PROCESS); SetBit (mud_info.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 (mud_info.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 (mud_info.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 (mud_info.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 (mud_info.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); 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]); 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; 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; #ifdef HAVE_SETITIMER int vt_set = 0; #endif 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->showstr_point) show_string (d, d->incomm); else if (d->pString) string_add (d->character, d->incomm); else switch (d->connected) { case CON_PLAYING: substitute_alias (d, d->incomm); break; default: nanny (d, d->incomm); break; } d->incomm[0] = '\0'; } } #ifndef DISABLE_I3 I3_loop (); #endif update_handler (); #ifndef DISABLE_WEBSRV update_web_server (); #endif 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; } bool read_from_descriptor (Descriptor * d) { unsigned int iStart, index; static unsigned char buf[sizeof (d->inbuf)]; memset (buf, 0, sizeof (buf)); if (!NullStr (d->incomm)) return true; iStart = strlen (d->inbuf); index = 0; if (iStart >= sizeof (d->inbuf) - 10) { logf ("%s input overflow!", d->host); d_write (d, NEWLINE "*** PUT A LID ON IT!!! ***" NEWLINE, 0); d->inbuf[sizeof (d->inbuf) - 10] = '\0'; return true; } for (;;) { int nRead; if (sizeof (buf) - 10 - iStart == 0) { break; } nRead = recv (d->descriptor, (char *) buf + index, sizeof (buf) - 10 - index, 0); if (nRead > 0) { index += nRead; if (buf[index - 1] == '\n' || buf[index - 1] == '\r') break; } else if (nRead == 0) { logf ("EOF encountered on read."); return false; } else if (check_errno (EWOULDBLOCK)) break; else { socket_error ("Read_from_descriptor"); return false; } } process_telnet (d, index, buf); if (d->connected == CON_GET_TERM && (IsSet (d->desc_flags, DESC_TELOPT_EOR | DESC_TELOPT_ECHO | DESC_TELOPT_NAWS | DESC_MXP | DESC_MSP | DESC_PUEBLO | DESC_TELOPT_TTYPE | DESC_TELOPT_BINARY | DESC_PORTAL | DESC_IMP) #ifndef DISABLE_MCCP || d->out_compress #endif )) { SetBit (d->desc_flags, DESC_COLOR); d_printlnf (d, "%s{c enabled Automatically...{x", Upper (colorize ("color"))); show_greeting (d); d->connected = CON_GET_NAME; } return true; } 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 (isascii (d->inbuf[i]) && isprint (d->inbuf[i])) 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; } #define CAN_SHOW_PROMPT ((!IsNPC(ch) && IsSet(ch->act, PLR_AUTOPROMPT)) \ || (d->fcommand && !d->run_buf) || ch->fighting) #include "comm_descriptor.h" #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; } int chprint (CharData * ch, const char *txt) { if (!NullStr (txt) && ch && ch->desc != NULL) return d_print (ch->desc, txt); return 0; } int chprintln (CharData * ch, const char *txt) { if (ch && ch->desc != NULL) { return (d_print (ch->desc, txt) + d_print (ch->desc, NEWLINE)); } return 0; } 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; 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) { 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; } int chprintf (CharData * ch, const char *fmt, ...) { char buf[MPL]; va_list args; if (NullStr (fmt) || !ch->desc) return 0; va_start (args, fmt); vsnprintf (buf, sizeof (buf), fmt, args); va_end (args); return d_print (ch->desc, buf); } int chprintlnf (CharData * ch, const char *fmt, ...) { char buf[MPL]; if (!ch || !ch->desc) return 0; buf[0] = NUL; if (!NullStr (fmt)) { va_list args; va_start (args, fmt); vsnprintf (buf, sizeof (buf), fmt, args); va_end (args); } return d_println (ch->desc, buf); } 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; SetBit (pMob->area->area_flags, AREA_CHANGED); } } for (pObj = obj_index_hash[hash]; pObj; pObj = pObj->next) { AffectData *paf; if (pObj->level >= imm_level) { pObj->level += mod; SetBit (pObj->area->area_flags, AREA_CHANGED); } 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; SetBit (pObj->area->area_flags, AREA_CHANGED); } break; default: break; } for (paf = pObj->affect_first; paf; paf = paf->next) { if (paf->level >= imm_level) { paf->level += mod; SetBit (pObj->area->area_flags, AREA_CHANGED); } } } } 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; }