/tomenet-4.5.3a/src/server/util.c
C | 6345 lines | 4074 code | 925 blank | 1346 comment | 1844 complexity | e46793e4ad0c5450d584d2ecba52feef MD5 | raw file
Possible License(s): 0BSD
Large files files are truncated, but you can click here to view the full file
- /* $Id$ */
- /* File: util.c */
- /* Purpose: Angband utilities -BEN- */
- #define SERVER
- #include "angband.h"
- #ifdef TOMENET_WORLDS
- #include "../world/world.h"
- #endif
- #ifdef MINGW
- /* For gettimeofday */
- #include <sys/time.h>
- #endif
- static void console_talk_aux(char *message);
- //static int name_lookup_loose_quiet(int Ind, cptr name, u16b party);
- #ifndef HAS_MEMSET
- /*
- * For those systems that don't have "memset()"
- *
- * Set the value of each of 'n' bytes starting at 's' to 'c', return 's'
- * If 'n' is negative, you will erase a whole lot of memory.
- */
- char *memset(char *s, int c, huge n)
- {
- char *t;
- for (t = s; n--; ) *t++ = c;
- return (s);
- }
- #endif
- #ifndef HAS_STRICMP
- /*
- * For those systems that don't have "stricmp()"
- *
- * Compare the two strings "a" and "b" ala "strcmp()" ignoring case.
- */
- int stricmp(cptr a, cptr b)
- {
- cptr s1, s2;
- char z1, z2;
- /* Scan the strings */
- for (s1 = a, s2 = b; TRUE; s1++, s2++)
- {
- z1 = FORCEUPPER(*s1);
- z2 = FORCEUPPER(*s2);
- if (z1 < z2) return (-1);
- if (z1 > z2) return (1);
- if (!z1) return (0);
- }
- }
- #endif
- bool in_banlist(char *addr){
- struct ip_ban *ptr;
- for(ptr=banlist; ptr!=(struct ip_ban*)NULL; ptr=ptr->next){
- if(!strcmp(addr, ptr->ip)) return(TRUE);
- }
- return(FALSE);
- }
- void check_banlist(){
- struct ip_ban *ptr, *new, *old=(struct ip_ban*)NULL;
- ptr=banlist;
- while(ptr!=(struct ip_ban*)NULL){
- if(ptr->time){
- if(!(--ptr->time)){
- s_printf("Unbanning connections from %s\n", ptr->ip);
- if(!old){
- banlist=ptr->next;
- new=banlist;
- }
- else{
- old->next=ptr->next;
- new=old->next;
- }
- free(ptr);
- ptr=new;
- continue;
- }
- }
- ptr=ptr->next;
- }
- }
- #ifdef SET_UID
- # ifndef HAS_USLEEP
- /*
- * For those systems that don't have "usleep()" but need it.
- *
- * Fake "usleep()" function grabbed from the inl netrek server -cba
- */
- static int usleep(huge microSeconds)
- {
- struct timeval Timer;
- int nfds = 0;
- #ifdef FD_SET
- fd_set *no_fds = NULL;
- #else
- int *no_fds = NULL;
- #endif
- /* Was: int readfds, writefds, exceptfds; */
- /* Was: readfds = writefds = exceptfds = 0; */
- /* Paranoia -- No excessive sleeping */
- if (microSeconds > 4000000L) core("Illegal usleep() call");
- /* Wait for it */
- Timer.tv_sec = (microSeconds / 1000000L);
- Timer.tv_usec = (microSeconds % 1000000L);
- /* Wait for it */
- if (select(nfds, no_fds, no_fds, no_fds, &Timer) < 0)
- {
- /* Hack -- ignore interrupts */
- if (errno != EINTR) return -1;
- }
- /* Success */
- return 0;
- }
- # endif
- /*
- * Hack -- External functions
- */
- extern struct passwd *getpwuid();
- extern struct passwd *getpwnam();
- /*
- * Find a default user name from the system.
- */
- void user_name(char *buf, int id)
- {
- struct passwd *pw;
- /* Look up the user name */
- if ((pw = getpwuid(id)))
- {
- (void)strcpy(buf, pw->pw_name);
- buf[16] = '\0';
- #ifdef CAPITALIZE_USER_NAME
- /* Hack -- capitalize the user name */
- if (islower(buf[0])) buf[0] = toupper(buf[0]);
- #endif
- return;
- }
- /* Oops. Hack -- default to "PLAYER" */
- strcpy(buf, "PLAYER");
- }
- #endif /* SET_UID */
- /*
- * The concept of the "file" routines below (and elsewhere) is that all
- * file handling should be done using as few routines as possible, since
- * every machine is slightly different, but these routines always have the
- * same semantics.
- *
- * In fact, perhaps we should use the "path_parse()" routine below to convert
- * from "canonical" filenames (optional leading tilde's, internal wildcards,
- * slash as the path seperator, etc) to "system" filenames (no special symbols,
- * system-specific path seperator, etc). This would allow the program itself
- * to assume that all filenames are "Unix" filenames, and explicitly "extract"
- * such filenames if needed (by "path_parse()", or perhaps "path_canon()").
- *
- * Note that "path_temp" should probably return a "canonical" filename.
- *
- * Note that "my_fopen()" and "my_open()" and "my_make()" and "my_kill()"
- * and "my_move()" and "my_copy()" should all take "canonical" filenames.
- *
- * Note that "canonical" filenames use a leading "slash" to indicate an absolute
- * path, and a leading "tilde" to indicate a special directory, and default to a
- * relative path, but MSDOS uses a leading "drivename plus colon" to indicate the
- * use of a "special drive", and then the rest of the path is parsed "normally",
- * and MACINTOSH uses a leading colon to indicate a relative path, and an embedded
- * colon to indicate a "drive plus absolute path", and finally defaults to a file
- * in the current working directory, which may or may not be defined.
- *
- * We should probably parse a leading "~~/" as referring to "ANGBAND_DIR". (?)
- */
- #ifdef ACORN
- /*
- * Most of the "file" routines for "ACORN" should be in "main-acn.c"
- */
- #else /* ACORN */
- #ifdef SET_UID
- /*
- * Extract a "parsed" path from an initial filename
- * Normally, we simply copy the filename into the buffer
- * But leading tilde symbols must be handled in a special way
- * Replace "~user/" by the home directory of the user named "user"
- * Replace "~/" by the home directory of the current user
- */
- errr path_parse(char *buf, int max, cptr file)
- {
- cptr u, s;
- struct passwd *pw;
- char user[128];
- /* Assume no result */
- buf[0] = '\0';
- /* No file? */
- if (!file) return (-1);
- /* File needs no parsing */
- if (file[0] != '~')
- {
- strcpy(buf, file);
- return (0);
- }
- /* Point at the user */
- u = file+1;
- /* Look for non-user portion of the file */
- s = strstr(u, PATH_SEP);
- /* Hack -- no long user names */
- if (s && (s >= u + sizeof(user))) return (1);
- /* Extract a user name */
- if (s)
- {
- int i;
- for (i = 0; u < s; ++i) user[i] = *u++;
- user[i] = '\0';
- u = user;
- }
- /* Look up the "current" user */
- if (u[0] == '\0') u = getlogin();
- /* Look up a user (or "current" user) */
- if (u) pw = getpwnam(u);
- else pw = getpwuid(getuid());
- /* Nothing found? */
- if (!pw) return (1);
- /* Make use of the info */
- (void)strcpy(buf, pw->pw_dir);
- /* Append the rest of the filename, if any */
- if (s) (void)strcat(buf, s);
- /* Success */
- return (0);
- }
- #else /* SET_UID */
- /*
- * Extract a "parsed" path from an initial filename
- *
- * This requires no special processing on simple machines,
- * except for verifying the size of the filename.
- */
- errr path_parse(char *buf, int max, cptr file)
- {
- /* Accept the filename */
- strnfmt(buf, max, "%s", file);
- /* Success */
- return (0);
- }
- #endif /* SET_UID */
- /*
- * Hack -- acquire a "temporary" file name if possible
- *
- * This filename is always in "system-specific" form.
- */
- errr path_temp(char *buf, int max)
- {
- #ifdef WINDOWS
- static u32b tmp_counter;
- static char valid_characters[] =
- "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
- char rand_ext[4];
- rand_ext[0] = valid_characters[rand_int(sizeof (valid_characters))];
- rand_ext[1] = valid_characters[rand_int(sizeof (valid_characters))];
- rand_ext[2] = valid_characters[rand_int(sizeof (valid_characters))];
- rand_ext[3] = '\0';
- strnfmt(buf, max, "%s/server_%ud.%s", ANGBAND_DIR_DATA, tmp_counter, rand_ext);
- tmp_counter++;
- #else
- cptr s;
- /* Temp file */
- s = tmpnam(NULL);
- /* Oops */
- if (!s) return (-1);
- /* Format to length */
- strnfmt(buf, max, "%s", s);
- #endif
- /* Success */
- return (0);
- }
- /*
- * Hack -- replacement for "fopen()"
- */
- FILE *my_fopen(cptr file, cptr mode)
- {
- char buf[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (NULL);
- /* Attempt to fopen the file anyway */
- return (fopen(buf, mode));
- }
- /*
- * Hack -- replacement for "fclose()"
- */
- errr my_fclose(FILE *fff)
- {
- /* Require a file */
- if (!fff) return (-1);
- /* Close, check for error */
- if (fclose(fff) == EOF) return (1);
- /* Success */
- return (0);
- }
- #endif /* ACORN */
- /*
- * Hack -- replacement for "fgets()"
- *
- * Read a string, without a newline, to a file
- *
- * Process tabs, strip internal non-printables
- */
- errr my_fgets(FILE *fff, char *buf, huge n, bool conv)
- {
- huge i = 0;
- char *s;
- char tmp[1024];
- /* Read a line */
- if (fgets(tmp, 1024, fff))
- {
- /* Convert weirdness */
- for (s = tmp; *s; s++)
- {
- /* Handle newline */
- if (*s == '\n')
- {
- /* Terminate */
- buf[i] = '\0';
- /* Success */
- return (0);
- }
- /* Handle tabs */
- else if (*s == '\t')
- {
- /* Hack -- require room */
- if (i + 8 >= n) break;
- /* Append a space */
- buf[i++] = ' ';
- /* Append some more spaces */
- while (!(i % 8)) buf[i++] = ' ';
- }
- /* Handle printables */
- else if (isprint(*s) || *s=='\377')
- {
- /* easier to edit perma files */
- if(conv && *s=='{' && *(s+1)!='{')
- *s='\377';
- /* Copy */
- buf[i++] = *s;
- /* Check length */
- if (i >= n) break;
- }
- }
- }
- /* Nothing */
- buf[0] = '\0';
- /* Failure */
- return (1);
- }
- /*
- * Hack -- replacement for "fputs()"
- *
- * Dump a string, plus a newline, to a file
- *
- * XXX XXX XXX Process internal weirdness?
- */
- errr my_fputs(FILE *fff, cptr buf, huge n)
- {
- /* XXX XXX */
- n = n ? n : 0;
- /* Dump, ignore errors */
- (void)fprintf(fff, "%s\n", buf);
- /* Success */
- return (0);
- }
- #ifdef ACORN
- /*
- * Most of the "file" routines for "ACORN" should be in "main-acn.c"
- *
- * Many of them can be rewritten now that only "fd_open()" and "fd_make()"
- * and "my_fopen()" should ever create files.
- */
- #else /* ACORN */
- /*
- * Code Warrior is a little weird about some functions
- */
- #ifdef BEN_HACK
- extern int open(const char *, int, ...);
- extern int close(int);
- extern int read(int, void *, unsigned int);
- extern int write(int, const void *, unsigned int);
- extern long lseek(int, long, int);
- #endif /* BEN_HACK */
- /*
- * The Macintosh is a little bit brain-dead sometimes
- */
- #ifdef MACINTOSH
- # define open(N,F,M) open((char*)(N),F)
- # define write(F,B,S) write(F,(char*)(B),S)
- #endif /* MACINTOSH */
- /*
- * Several systems have no "O_BINARY" flag
- */
- #ifndef O_BINARY
- # define O_BINARY 0
- #endif /* O_BINARY */
- /*
- * Hack -- attempt to delete a file
- */
- errr fd_kill(cptr file)
- {
- char buf[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (-1);
- /* Remove */
- (void)remove(buf);
- /* XXX XXX XXX */
- return (0);
- }
- /*
- * Hack -- attempt to move a file
- */
- errr fd_move(cptr file, cptr what)
- {
- char buf[1024];
- char aux[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (-1);
- /* Hack -- Try to parse the path */
- if (path_parse(aux, 1024, what)) return (-1);
- /* Rename */
- (void)rename(buf, aux);
- /* XXX XXX XXX */
- return (0);
- }
- /*
- * Hack -- attempt to copy a file
- */
- errr fd_copy(cptr file, cptr what)
- {
- char buf[1024];
- char aux[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (-1);
- /* Hack -- Try to parse the path */
- if (path_parse(aux, 1024, what)) return (-1);
- /* Copy XXX XXX XXX */
- /* (void)rename(buf, aux); */
- /* XXX XXX XXX */
- return (1);
- }
- /*
- * Hack -- attempt to open a file descriptor (create file)
- *
- * This function should fail if the file already exists
- *
- * Note that we assume that the file should be "binary"
- *
- * XXX XXX XXX The horrible "BEN_HACK" code is for compiling under
- * the CodeWarrior compiler, in which case, for some reason, none
- * of the "O_*" flags are defined, and we must fake the definition
- * of "O_RDONLY", "O_WRONLY", and "O_RDWR" in "A-win-h", and then
- * we must simulate the effect of the proper "open()" call below.
- */
- int fd_make(cptr file, int mode)
- {
- char buf[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (-1);
- #ifdef BEN_HACK
- /* Check for existance */
- /* if (fd_close(fd_open(file, O_RDONLY | O_BINARY))) return (1); */
- /* Mega-Hack -- Create the file */
- (void)my_fclose(my_fopen(file, "wb"));
- /* Re-open the file for writing */
- return (open(buf, O_WRONLY | O_BINARY, mode));
- #else /* BEN_HACK */
- /* Create the file, fail if exists, write-only, binary */
- return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
- #endif /* BEN_HACK */
- }
- /*
- * Hack -- attempt to open a file descriptor (existing file)
- *
- * Note that we assume that the file should be "binary"
- */
- int fd_open(cptr file, int flags)
- {
- char buf[1024];
- /* Hack -- Try to parse the path */
- if (path_parse(buf, 1024, file)) return (-1);
- /* Attempt to open the file */
- return (open(buf, flags | O_BINARY, 0));
- }
- /*
- * Hack -- attempt to lock a file descriptor
- *
- * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
- */
- errr fd_lock(int fd, int what)
- {
- /* XXX XXX */
- what = what ? what : 0;
- /* Verify the fd */
- if (fd < 0) return (-1);
- #ifdef SET_UID
- # ifdef USG
- /* Un-Lock */
- if (what == F_UNLCK)
- {
- /* Unlock it, Ignore errors */
- lockf(fd, F_ULOCK, 0);
- }
- /* Lock */
- else
- {
- /* Lock the score file */
- if (lockf(fd, F_LOCK, 0) != 0) return (1);
- }
- #else
- /* Un-Lock */
- if (what == F_UNLCK)
- {
- /* Unlock it, Ignore errors */
- (void)flock(fd, LOCK_UN);
- }
- /* Lock */
- else
- {
- /* Lock the score file */
- if (flock(fd, LOCK_EX) != 0) return (1);
- }
- # endif
- #endif
- /* Success */
- return (0);
- }
- /*
- * Hack -- attempt to seek on a file descriptor
- */
- errr fd_seek(int fd, huge n)
- {
- huge p;
- /* Verify fd */
- if (fd < 0) return (-1);
- /* Seek to the given position */
- p = lseek(fd, n, SEEK_SET);
- /* Failure */
- if (p == (huge) -1) return (1);
- /* Failure */
- if (p != n) return (1);
- /* Success */
- return (0);
- }
- /*
- * Hack -- attempt to read data from a file descriptor
- */
- errr fd_read(int fd, char *buf, huge n)
- {
- /* Verify the fd */
- if (fd < 0) return (-1);
- #ifndef SET_UID
- /* Read pieces */
- while (n >= 16384)
- {
- /* Read a piece */
- if (read(fd, buf, 16384) != 16384) return (1);
- /* Shorten the task */
- buf += 16384;
- /* Shorten the task */
- n -= 16384;
- }
- #endif
- /* Read the final piece */
- if ((huge) read(fd, buf, n) != n) return (1);
- /* Success */
- return (0);
- }
- /*
- * Hack -- Attempt to write data to a file descriptor
- */
- errr fd_write(int fd, cptr buf, huge n)
- {
- /* Verify the fd */
- if (fd < 0) return (-1);
- #ifndef SET_UID
- /* Write pieces */
- while (n >= 16384)
- {
- /* Write a piece */
- if (write(fd, buf, 16384) != 16384) return (1);
- /* Shorten the task */
- buf += 16384;
- /* Shorten the task */
- n -= 16384;
- }
- #endif
- /* Write the final piece */
- if ((huge) write(fd, buf, n) != n) return (1);
- /* Success */
- return (0);
- }
- /*
- * Hack -- attempt to close a file descriptor
- */
- errr fd_close(int fd)
- {
- /* Verify the fd */
- if (fd < 0) return (-1);
- /* Close */
- (void)close(fd);
- /* XXX XXX XXX */
- return (0);
- }
- #endif /* ACORN */
- /*
- * Convert a decimal to a single digit octal number
- */
- static char octify(uint i)
- {
- return (hexsym[i%8]);
- }
- /*
- * Convert a decimal to a single digit hex number
- */
- static char hexify(uint i)
- {
- return (hexsym[i%16]);
- }
- /*
- * Convert a octal-digit into a decimal
- */
- static int deoct(char c)
- {
- if (isdigit(c)) return (D2I(c));
- return (0);
- }
- /*
- * Convert a hexidecimal-digit into a decimal
- */
- static int dehex(char c)
- {
- if (isdigit(c)) return (D2I(c));
- if (islower(c)) return (A2I(c) + 10);
- if (isupper(c)) return (A2I(tolower(c)) + 10);
- return (0);
- }
- /*
- * Hack -- convert a printable string into real ascii
- *
- * I have no clue if this function correctly handles, for example,
- * parsing "\xFF" into a (signed) char. Whoever thought of making
- * the "sign" of a "char" undefined is a complete moron. Oh well.
- */
- void text_to_ascii(char *buf, cptr str)
- {
- char *s = buf;
- /* Analyze the "ascii" string */
- while (*str)
- {
- /* Backslash codes */
- if (*str == '\\')
- {
- /* Skip the backslash */
- str++;
- /* Hex-mode XXX */
- if (*str == 'x')
- {
- *s = 16 * dehex(*++str);
- *s++ += dehex(*++str);
- }
- /* Hack -- simple way to specify "backslash" */
- else if (*str == '\\')
- {
- *s++ = '\\';
- }
- /* Hack -- simple way to specify "caret" */
- else if (*str == '^')
- {
- *s++ = '^';
- }
- /* Hack -- simple way to specify "space" */
- else if (*str == 's')
- {
- *s++ = ' ';
- }
- /* Hack -- simple way to specify Escape */
- else if (*str == 'e')
- {
- *s++ = ESCAPE;
- }
- /* Backspace */
- else if (*str == 'b')
- {
- *s++ = '\b';
- }
- /* Newline */
- else if (*str == 'n')
- {
- *s++ = '\n';
- }
- /* Return */
- else if (*str == 'r')
- {
- *s++ = '\r';
- }
- /* Tab */
- else if (*str == 't')
- {
- *s++ = '\t';
- }
- /* Octal-mode */
- else if (*str == '0')
- {
- *s = 8 * deoct(*++str);
- *s++ += deoct(*++str);
- }
- /* Octal-mode */
- else if (*str == '1')
- {
- *s = 64 + 8 * deoct(*++str);
- *s++ += deoct(*++str);
- }
- /* Octal-mode */
- else if (*str == '2')
- {
- *s = 64 * 2 + 8 * deoct(*++str);
- *s++ += deoct(*++str);
- }
- /* Octal-mode */
- else if (*str == '3')
- {
- *s = 64 * 3 + 8 * deoct(*++str);
- *s++ += deoct(*++str);
- }
- /* Skip the final char */
- str++;
- }
- /* Normal Control codes */
- else if (*str == '^')
- {
- str++;
- *s++ = (*str++ & 037);
- }
- /* Normal chars */
- else
- {
- *s++ = *str++;
- }
- }
- /* Terminate */
- *s = '\0';
- }
- /*
- * Hack -- convert a string into a printable form
- */
- void ascii_to_text(char *buf, cptr str)
- {
- char *s = buf;
- /* Analyze the "ascii" string */
- while (*str)
- {
- byte i = (byte)(*str++);
- if (i == ESCAPE)
- {
- *s++ = '\\';
- *s++ = 'e';
- }
- else if (i == ' ')
- {
- *s++ = '\\';
- *s++ = 's';
- }
- else if (i == '\b')
- {
- *s++ = '\\';
- *s++ = 'b';
- }
- else if (i == '\t')
- {
- *s++ = '\\';
- *s++ = 't';
- }
- else if (i == '\n')
- {
- *s++ = '\\';
- *s++ = 'n';
- }
- else if (i == '\r')
- {
- *s++ = '\\';
- *s++ = 'r';
- }
- else if (i == '^')
- {
- *s++ = '\\';
- *s++ = '^';
- }
- else if (i == '\\')
- {
- *s++ = '\\';
- *s++ = '\\';
- }
- else if (i < 32)
- {
- *s++ = '^';
- *s++ = i + 64;
- }
- else if (i < 127)
- {
- *s++ = i;
- }
- else if (i < 64)
- {
- *s++ = '\\';
- *s++ = '0';
- *s++ = octify(i / 8);
- *s++ = octify(i % 8);
- }
- else
- {
- *s++ = '\\';
- *s++ = 'x';
- *s++ = hexify(i / 16);
- *s++ = hexify(i % 16);
- }
- }
- /* Terminate */
- *s = '\0';
- }
- /*
- * Local variable -- we are inside a "control-underscore" sequence
- */
- /*static bool parse_under = FALSE;*/
- /*
- * Local variable -- we are inside a "control-backslash" sequence
- */
- /*static bool parse_slash = FALSE;*/
- /*
- * Local variable -- we are stripping symbols for a while
- */
- /*static bool strip_chars = FALSE;*/
- /*
- * Flush the screen, make a noise
- */
- void bell(void)
- {
- }
- /*
- * Mega-Hack -- Make a (relevant?) sound
- */
- #ifndef USE_SOUND_2010
- void sound(int Ind, int val) {
- // Send_sound(Ind, val);
- Send_sound(Ind, val, 0, 0, 100, 0);
- }
- #else
- /* 'type' is used client-side, for efficiency options concerning near-simultaneous sounds
- 'nearby' means if other players nearby would be able to also hear the sound. - C. Blue */
- void sound(int Ind, cptr name, cptr alternative, int type, bool nearby) {
- #if 0 /* non-optimized way (causes LUA errors if sound() is called in fire_ball() which is in turn called from LUA - C. Blue */
- int val, val2;
- val = exec_lua(0, format("return get_sound_index(\"%s\")", name));
- if (alternative) {
- val2 = exec_lua(0, format("return get_sound_index(\"%s\")", alternative));
- } else {
- val2 = -1;
- }
- #else /* optimized way... */
- int val = -1, val2 = -1, i, d;
- if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], name)) {
- val = i;
- break;
- }
- }
- if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], alternative)) {
- val2 = i;
- break;
- }
- }
- #endif
- // if (is_admin(Players[Ind])) s_printf("USE_SOUND_2010: looking up sound %s -> %d.\n", name, val);
- if (val == -1) {
- if (val2 != -1) {
- /* Use the alternative instead */
- val = val2;
- val2 = -1;
- } else {
- return;
- }
- }
- /* also send sounds to nearby players, depending on sound or sound type */
- if (nearby) {
- for (i = 1; i <= NumPlayers; i++) {
- if (Players[i]->conn == NOT_CONNECTED) continue;
- if (!inarea(&Players[i]->wpos, &Players[Ind]->wpos)) continue;
- if (Ind == i) continue;
- d = distance(Players[Ind]->py, Players[Ind]->px, Players[i]->py, Players[i]->px);
- #if 0
- if (d > 10) continue;
- if (d == 0) d = 1; //paranoia oO
- Send_sound(i, val, val2, type, 100 / d, Players[Ind]->id);
- // Send_sound(i, val, val2, type, (6 - d) * 20, Players[Ind]->id); hm or this?
- #else
- if (d > MAX_SIGHT) continue;
- d += 3;
- d /= 2;
- Send_sound(i, val, val2, type, 100 / d, Players[Ind]->id);
- #endif
- }
- }
- Send_sound(Ind, val, val2, type, 100, Players[Ind]->id);
- }
- /* send sound to player and everyone nearby at full volume, similar to
- msg_..._near(), except it also sends to the player himself.
- This is used for highly important and *loud* sounds such as 'shriek' - C. Blue */
- void sound_near(int Ind, cptr name, cptr alternative, int type) {
- int i, d;
- for (i = 1; i <= NumPlayers; i++) {
- if (Players[i]->conn == NOT_CONNECTED) continue;
- if (!inarea(&Players[i]->wpos, &Players[Ind]->wpos)) continue;
- /* Can he see this player? */
- // if (!(Players[i]->cave_flag[Players[Ind]->py][Players[Ind]->px] & CAVE_VIEW)) continue;
- /* within audible range? */
- d = distance(Players[Ind]->py, Players[Ind]->px, Players[i]->py, Players[i]->px);
- if (d > MAX_SIGHT) continue;
- sound(i, name, alternative, type, FALSE);
- }
- }
- /* send sound to all players nearby a certain location, and allow to specify
- a player to exclude, same as msg_print_near_site() for messages. - C. Blue */
- void sound_near_site(int y, int x, worldpos *wpos, int Ind, cptr name, cptr alternative, int type, bool viewable) {
- int i, d;
- player_type *p_ptr;
- int val = -1, val2 = -1;
- if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], name)) {
- val = i;
- break;
- }
- }
- if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], alternative)) {
- val2 = i;
- break;
- }
- }
- if (val == -1) {
- if (val2 != -1) {
- /* Use the alternative instead */
- val = val2;
- val2 = -1;
- } else {
- return;
- }
- }
- /* Check each player */
- for (i = 1; i <= NumPlayers; i++) {
- /* Check this player */
- p_ptr = Players[i];
- /* Make sure this player is in the game */
- if (p_ptr->conn == NOT_CONNECTED) continue;
- /* Skip specified player, if any */
- if (i == Ind) continue;
- /* Make sure this player is at this depth */
- if (!inarea(&p_ptr->wpos, wpos)) continue;
- /* Can (s)he see the site? */
- if (viewable && !(p_ptr->cave_flag[y][x] & CAVE_VIEW)) continue;
- /* within audible range? */
- d = distance(y, x, Players[i]->py, Players[i]->px);
- /* NOTE: should be consistent with msg_print_near_site() */
- if (d > MAX_SIGHT) continue;
- #if 0
- /* limit for volume calc */
- if (d > 20) d = 20;
- d += 3;
- d /= 3;
- Send_sound(i, val, val2, type, 100 / d, 0);
- #else
- /* limit for volume calc */
- Send_sound(i, val, val2, type, 100 - (d * 50) / 11, 0);
- #endif
- }
- }
- /* like msg_print_near_monster() just for sounds,
- basically same as sound_near_site() - C. Blue */
- void sound_near_monster(int m_idx, cptr name, cptr alternative, int type) {
- int i, d;
- player_type *p_ptr;
- cave_type **zcave;
- monster_type *m_ptr = &m_list[m_idx];
- worldpos *wpos = &m_ptr->wpos;
- int val = -1, val2 = -1;
- if (!(zcave = getcave(wpos))) return;
- if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], name)) {
- val = i;
- break;
- }
- }
- if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
- if (!audio_sfx[i][0]) break;
- if (!strcmp(audio_sfx[i], alternative)) {
- val2 = i;
- break;
- }
- }
- if (val == -1) {
- if (val2 != -1) {
- /* Use the alternative instead */
- val = val2;
- val2 = -1;
- } else {
- return;
- }
- }
- /* Check each player */
- for (i = 1; i <= NumPlayers; i++) {
- /* Check this player */
- p_ptr = Players[i];
- /* Make sure this player is in the game */
- if (p_ptr->conn == NOT_CONNECTED) continue;
- /* Make sure this player is at this depth */
- if (!inarea(&p_ptr->wpos, wpos)) continue;
- /* Skip if not visible */
- // if (!p_ptr->mon_vis[m_idx]) continue;
- /* Can he see this player? */
- // if (!p_ptr->cave_flag[y][x] & CAVE_VIEW) continue;
- /* Can (s)he see the site? */
- // if (!(p_ptr->cave_flag[y][x] & CAVE_VIEW)) continue;
- /* within audible range? */
- d = distance(m_ptr->fy, m_ptr->fx, Players[i]->py, Players[i]->px);
- /* NOTE: should be consistent with msg_print_near_site() */
- if (d > MAX_SIGHT) continue;
- #if 0
- /* limit for volume calc */
- if (d > 20) d = 20;
- d += 3;
- d /= 3;
- Send_sound(i, val, val2, type, 100 / d, 0);
- #else
- /* limit for volume calc */
- Send_sound(i, val, val2, type, 100 - (d * 50) / 11, 0);
- #endif
- }
- }
- /* find correct music for the player based on his current location - C. Blue */
- void handle_music(int Ind) {
- player_type *p_ptr = Players[Ind];
- dun_level *l_ptr = NULL;
- int i = -1, tmus = 0, tmus_inverse = 0;
- cave_type **zcave = getcave(&p_ptr->wpos);
- #ifdef ARCADE_SERVER
- /* Special music for Arcade Server stuff */
- if (p_ptr->wpos.wx == WPOS_ARCADE_X && p_ptr->wpos.wy == WPOS_ARCADE_Y
- // && p_ptr->wpos.wz == WPOS_ARCADE_Z
- ) {
- p_ptr->music_monster = -2;
- if (p_ptr->wpos.wz == 0) Send_music(Ind, 1); /* 'generic town' music instead of Bree default */
- else {
- //47 and 48 are actually pieces used in other arena events
- if (rand_int(2)) Send_music(Ind, 47);
- else Send_music(Ind, 48);
- }
- return;
- }
- #endif
- if (p_ptr->wpos.wz != 0) {
- l_ptr = getfloor(&p_ptr->wpos);
- if (p_ptr->wpos.wz < 0)
- i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].dungeon->type;
- else
- i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].tower->type;
- }
- if (getlevel(&p_ptr->wpos) == 196) {
- //Zu-Aon
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 45);
- return;
- } else if ((i != -1) && (l_ptr->flags1 & LF1_NO_GHOST)) {
- //Morgoth
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 44);
- return;
- }
- if (getlevel(&p_ptr->wpos) == 200) {
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 8); //Valinor
- return;
- } else if (p_ptr->wpos.wx == WPOS_PVPARENA_X &&
- p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z) {
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 47); //PvP Arena
- return;
- } else if (ge_special_sector && p_ptr->wpos.wx == WPOS_ARENA_X &&
- p_ptr->wpos.wy == WPOS_ARENA_Y && p_ptr->wpos.wz == WPOS_ARENA_Z) {
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 48); //Monster Arena Challenge
- return;
- } else if (sector00separation && p_ptr->wpos.wx == WPOS_HIGHLANDER_X &&
- p_ptr->wpos.wy == WPOS_HIGHLANDER_Y && p_ptr->wpos.wz == WPOS_HIGHLANDER_Z) {
- //hack: init music as 'higher priority than boss-specific':
- p_ptr->music_monster = -2;
- Send_music(Ind, 47); //Highlander Tournament (death match phase)
- return;
- }
- /* No-tele grid: Re-use 'terrifying' bgm for this */
- if (zcave && (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK)) {
- #if 0 /* hack: init music as 'higher priority than boss-specific': */
- p_ptr->music_monster = -2;
- #endif
- Send_music(Ind, 46); //No-Tele vault
- return;
- }
- /* rest of the music has lower priority than already running, boss-specific music */
- if (p_ptr->music_monster != -1) return;
- /* on world surface */
- if (p_ptr->wpos.wz == 0) {
- /* play town music also in its surrounding area of houses, if we're coming from the town? */
- if (istownarea(&p_ptr->wpos, MAX_TOWNAREA)) {
- i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].town_idx;
- if (night_surface) switch (town[i].type) {
- default:
- case 0: tmus = 49; tmus_inverse = 1; break; //default town
- case 1: tmus = 50; tmus_inverse = 3; break; //Bree
- case 2: tmus = 51; tmus_inverse = 4; break; //Gondo
- case 3: tmus = 52; tmus_inverse = 5; break; //Minas
- case 4: tmus = 53; tmus_inverse = 6; break; //Loth
- case 5: tmus = 54; tmus_inverse = 7; break; //Khaz
- }
- else switch (town[i].type) {
- default:
- case 0: tmus = 1; tmus_inverse = 49; break; //default town
- case 1: tmus = 3; tmus_inverse = 50; break; //Bree
- case 2: tmus = 4; tmus_inverse = 51; break; //Gondo
- case 3: tmus = 5; tmus_inverse = 52; break; //Minas
- case 4: tmus = 6; tmus_inverse = 53; break; //Loth
- case 5: tmus = 7; tmus_inverse = 54; break; //Khaz
- }
- /* now the specialty: If we're coming from elsewhere,
- we only switch to town music when we enter the town.
- If we're coming from the town, however, we keep the
- music while being in its surrounding area of houses. */
- if (istown(&p_ptr->wpos) || p_ptr->music_current == tmus
- /* don't switch from town area music to wild music on day/night change: */
- || p_ptr->music_current == tmus_inverse)
- Send_music(Ind, tmus);
- else if (night_surface) Send_music(Ind, 10);
- else Send_music(Ind, 9);
- return;
- } else {
- if (night_surface) Send_music(Ind, 10);
- else Send_music(Ind, 9);
- return;
- }
- /* in the dungeon */
- } else {
- /* Dungeon towns have their own music to bolster the player's motivation ;) */
- if (isdungeontown(&p_ptr->wpos)) {
- if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) Send_music(Ind, 1); /* 'generic town' music instead, for a change */
- else Send_music(Ind, 2); /* the usual music for this case */
- return;
- }
- /* Floor-specific music (monster/boss-independant)? */
- if ((i != 6) /*not in Nether Realm, really ^^*/
- && (!(d_info[i].flags2 & DF2_NO_DEATH)) /* nor in easy dungeons */
- && !(p_ptr->wpos.wx == WPOS_PVPARENA_X /* and not in pvp-arena */
- && p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z))
- {
- if (p_ptr->distinct_floor_feeling || is_admin(p_ptr)) {
- if (l_ptr->flags2 & LF2_OOD_HI) {
- Send_music(Ind, 46);
- return;
- }
- }
- }
- //we could just look through audio.lua, by querying get_music_name() I guess..
- switch (i) {
- default:
- case 0:
- if (d_info[i].flags2 & DF2_NO_DEATH) Send_music(Ind, 12);
- else if (d_info[i].flags2 & DF2_IRON) Send_music(Ind, 13);
- else if ((d_info[i].flags2 & DF2_HELL) || (d_info[i].flags1 & DF1_FORCE_DOWN)) Send_music(Ind, 14);
- else Send_music(Ind, 11);
- return;
- case 1: Send_music(Ind, 32); return; //Mirkwood
- case 2: Send_music(Ind, 17); return; //Mordor
- case 3: Send_music(Ind, 19); return; //Angband
- case 4: Send_music(Ind, 16); return; //Barrow-Downs
- case 5: Send_music(Ind, 21); return; //Mount Doom
- case 6: Send_music(Ind, 22); return; //Nether Realm
- case 7: Send_music(Ind, 35); return; //Submerged Ruins
- case 8: Send_music(Ind, 26); return; //Halls of Mandos
- case 9: Send_music(Ind, 30); return; //Cirith Ungol
- case 10: Send_music(Ind, 28); return; //The Heart of the Earth
- case 16: Send_music(Ind, 18); return; //The Paths of the Dead
- case 17: Send_music(Ind, 37); return; //The Illusory Castle
- case 18: Send_music(Ind, 39); return; //The Maze
- case 19: Send_music(Ind, 20); return; //The Orc Cave
- case 20: Send_music(Ind, 36); return; //Erebor
- case 21: Send_music(Ind, 27); return; //The Old Forest
- case 22: Send_music(Ind, 29); return; //The Mines of Moria
- case 23: Send_music(Ind, 34); return; //Dol Guldur
- case 24: Send_music(Ind, 31); return; //The Small Water Cave
- case 25: Send_music(Ind, 38); return; //The Sacred Land of Mountains
- case 26: Send_music(Ind, 24); return; //The Land of Rhun
- case 27: Send_music(Ind, 25); return; //The Sandworm Lair
- case 28: Send_music(Ind, 33); return; //Death Fate
- case 29: Send_music(Ind, 23); return; //The Helcaraxe
- case 30: Send_music(Ind, 15); return; //The Training Tower
- }
- }
- /* Shouldn't happen - send default (dungeon) music */
- Send_music(Ind, 0);
- }
- /* generate an item-type specific sound, depending on the action applied to it
- action: 0 = pickup, 1 = drop, 2 = wear/wield, 3 = takeoff, 4 = throw, 5 = destroy */
- void sound_item(int Ind, int tval, int sval, cptr action) {
- char sound_name[30];
- cptr item = NULL;
- /* action hack: re-use sounds! */
- action = "item_";
- /* choose sound */
- if (is_weapon(tval)) switch(tval) {
- case TV_SWORD: item = "sword"; break;
- case TV_BLUNT:
- if (sval == SV_WHIP) item = "whip"; else item = "blunt";
- break;
- case TV_AXE: item = "axe"; break;
- case TV_POLEARM: item = "polearm"; break;
- } else if (is_armour(tval)) {
- if (is_textile_armour(tval, sval))
- item = "armor_light";
- else
- item = "armor_heavy";
- } else switch(tval) {
- /* equippable stuff */
- case TV_LITE: item = "lightsource"; break;
- case TV_RING: item = "ring"; break;
- case TV_AMULET: item = "amulet"; break;
- case TV_TOOL: item = "tool"; break;
- case TV_DIGGING: item = "tool_digger"; break;
- case TV_MSTAFF: item = "magestaff"; break;
- // case TV_BOOMERANG: item = ""; break;
- // case TV_BOW: item = ""; break;
- // case TV_SHOT: item = ""; break;
- // case TV_ARROW: item = ""; break;
- // case TV_BOLT: item = ""; break;
- /* other items */
- // case TV_BOOK: item = "book"; break;
- case TV_SCROLL: case TV_PARCHMENT:
- item = "scroll"; break;
- /* case TV_BOTTLE: item = "potion"; break;
- case TV_POTION: case TV_POTION2: case TV_FLASK:
- item = "potion"; break;*/
- case TV_RUNE:
- item = "rune"; break;
- // case TV_SKELETON: item = ""; break;
- case TV_FIRESTONE: item = "firestone"; break;
- /* case TV_SPIKE: item = ""; break;
- case TV_CHEST: item = ""; break;
- case TV_JUNK: item = ""; break;
- case TV_GAME: item = ""; break;
- case TV_TRAPKIT: item = ""; break;
- case TV_STAFF: item = ""; break;
- case TV_WAND: item = ""; break;
- case TV_ROD: item = ""; break;
- case TV_ROD_MAIN: item = ""; break;
- case TV_FOOD: item = ""; break;
- case TV_KEY: item = ""; break;
- case TV_GOLEM: item = ""; break;
- case TV_SPECIAL: item = ""; break;
- */ }
- /* no sound effect available? */
- if (item == NULL) return;
- /* build sound name from action and item */
- strcpy(sound_name, action);
- strcat(sound_name, item);
- /* off we go */
- sound(Ind, sound_name, NULL, SFX_TYPE_COMMAND, FALSE);
- }
- #endif
- /*
- * We use a global array for all inscriptions to reduce the memory
- * spent maintaining inscriptions. Of course, it is still possible
- * to run out of inscription memory, especially if too many different
- * inscriptions are used, but hopefully this will be rare.
- *
- * We use dynamic string allocation because otherwise it is necessary
- * to pre-guess the amount of quark activity. We limit the total
- * number of quarks, but this is much easier to "expand" as needed.
- *
- * Any two items with the same inscription will have the same "quark"
- * index, which should greatly reduce the need for inscription space.
- *
- * Note that "quark zero" is NULL and should not be "dereferenced".
- */
- /*
- * Add a new "quark" to the set of quarks.
- */
- s16b quark_add(cptr str)
- {
- int i;
- /* Look for an existing quark */
- for (i = 1; i < quark__num; i++)
- {
- /* Check for equality */
- if (streq(quark__str[i], str)) return (i);
- }
- /* Paranoia -- Require room */
- if (quark__num == QUARK_MAX) return (0);
- /* New maximal quark */
- quark__num = i + 1;
- /* Add a new quark */
- quark__str[i] = string_make(str);
- /* Return the index */
- return (i);
- }
- /*
- * This function looks up a quark
- */
- cptr quark_str(s16b i)
- {
- cptr q;
- /* Verify */
- if ((i < 0) || (i >= quark__num)) i = 0;
- /* Access the quark */
- q = quark__str[i];
- /* Return the quark */
- return (q);
- }
- /*
- * Check to make sure they haven't inscribed an item against what
- * they are trying to do -Crimson
- * look for "!*Erm" type, and "!* !A !f" type.
- */
- bool check_guard_inscription( s16b quark, char what ) {
- const char *ax;
- ax = quark_str(quark);
- if (ax == NULL) { return FALSE; };
- while ((ax=strchr(ax, '!')) != NULL) {
- while (ax++ != NULL) {
- if (*ax == 0) {
- return FALSE; /* end of quark, stop */
- }
- if (*ax == ' ' || *ax == '@' || *ax == '#') {
- break; /* end of segment, stop */
- }
- if (*ax == what) {
- return TRUE; /* exact match, stop */
- }
- if (*ax == '*') {
- /* why so much hassle? * = all, that's it */
- /* return TRUE; -- well, !'B'ash if it's on the ground sucks ;) */
- switch (what) { /* check for paranoid tags */
- case 'd': /* no drop */
- case 'h': /* no house ( sell a a key ) */
- case 'k': /* no destroy */
- case 's': /* no sell */
- case 'v': /* no thowing */
- case '=': /* force pickup */
- #if 0
- case 'w': /* no wear/wield */
- case 't': /* no take off */
- #endif
- return TRUE;
- };
- };
- /* Refilling is blocked if item must not be destroyed */
- if (what == 'F' && *ax == 'k') return TRUE;
- };
- };
- return FALSE;
- }
- /*
- * Output a message to the top line of the screen.
- *
- * Break long messages into multiple pieces (40-72 chars).
- *
- * Allow multiple short messages to "share" the top line.
- *
- * Prompt the user to make sure he has a chance to read them.
- *
- * These messages are memorized for later reference (see above).
- *
- * We could do "Term_fresh()" to provide "flicker" if needed.
- *
- * XXX XXX XXX Note that we must be very careful about using the
- * "msg_print()" functions without explicitly calling the special
- * "msg_print(NULL)" function, since this may result in the loss
- * of information if the screen is cleared, or if anything is
- * displayed on the top line.
- *
- * XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
- * even if no messages are pending. This is probably a hack.
- */
- bool suppress_message = FALSE, censor_message = FALSE, suppress_boni = FALSE;
- int censor_length = 0, censor_punish = 0;
- void msg_print(int Ind, cptr msg_raw)
- {
- char msg_dup[MSG_LEN], *msg = msg_dup;
- int line_len = 80; /* maximum length of a text line to be displayed;
- this is client-dependant, compare c_msg_print (c-util.c) */
- char msg_buf[line_len + 2 + 2 * 80]; /* buffer for 1 line. + 2 bytes for colour code (+2*80 bytes for colour codeeeezz) */
- char msg_minibuf[3]; /* temp buffer for adding characters */
- int text_len, msg_scan = 0, space_scan, tab_spacer = 0, tmp;
- char colour_code = 'w';
- bool no_colour_code = FALSE;
- bool first_character = TRUE;
- // bool is_chat = ((msg_raw != NULL) && (strlen(msg_raw) > 2) && (msg_raw[2] == '['));
- bool client_ctrlo = FALSE, client_chat = FALSE, client_all = FALSE;
- /* for {- feature */
- char prev_colour_code = 'w', first_colour_code = 'w';
- bool first_colour_code_set = FALSE;
- /* backward msg window width hack for windows clients (non-x11 clients rather) */
- if (!is_newer_than(&Players[Ind]->version, 4, 4, 5, 3, 0, 0) && !strcmp(Players[Ind]->realname, "PLAYER")) line_len = 72;
- /* Pfft, sorry to bother you.... --JIR-- */
- if (suppress_message) return;
- /* no message? */
- if (msg_raw == NULL) return;
- strcpy(msg_dup, msg_raw); /* in case msg_raw was constant */
- /* censor swear words? */
- if (censor_message) {
- /* skip the name of the sender, etc. */
- censor_punish = handle_censor(msg + strlen(msg) - censor_length);
- /* we just needed to get censor_punish at least once, above.
- Now don't really censor the string if the player doesn't want to.. */
- if (!Players[Ind]->censor_swearing) strcpy(msg_dup, msg_raw);
- }
- /* marker for client: add message to 'chat-only buffer', not to 'nochat buffer' */
- if (msg[0] == '\375') {
- client_chat = TRUE;
- msg++;
- /* hack: imply that chat-only messages are also always important messages */
- client_ctrlo = TRUE;
- }
- /* marker for client: add message to 'nochat buffer' AND to 'chat-only buffer' */
- else if (msg[0] == '\374') {
- client_all = TRUE;
- msg++;
- /* hack: imply that messages that go to chat-buffer are also always important messages */
- client_ctrlo = TRUE;
- }
- /* ADDITIONAL marker for client: add message to CTRL+O 'important scrollback buffer' */
- if (msg[0] == '\376') {
- client_ctrlo = TRUE;
- msg++;
- }
- /* note: neither \375 nor \374 means:
- add message to 'nochat buffer', but not to 'chat-only buffer' (default) */
- /* neutralize markers if client version too old */
- if (!is_newer_than(&Players[Ind]->version, 4, 4, 2, 0, 0, 0))
- client_ctrlo = client_chat = client_all = FALSE;
- #if 1 /* String longer than 1 line? -> Split it up! --C. Blue-- */
- while (msg != NULL && msg[msg_scan] != '\0') {
- /* Start a new line */
- strcpy(msg_buf, "");
- text_len = 0;
- /* Tabbing the line? */
- msg_minibuf[0] = ' ';
- msg_minibuf[1] = '\0';
- #if 0 /* 0'ed to remove backward compatibility via '~' character. We want to switch to \374..6 codes exlusively */
- if (is_chat && tab_spacer) {
- /* Start the padding for chat messages with '~' */
- strcat(msg_buf, "~");
- tmp = tab_spacer - 1;
- } else {
- tmp = tab_spacer;
- }
- #else
- tmp = tab_spacer;
- #endif
- while (tmp--) {
- text_len++;
- strcat(msg_buf, msg_minibuf);
- }
- /* Prefixing colour code? */
- if (colour_code) {
- msg_minibuf[0] = '\377';
- msg_minibuf[1] = colour_code;
- msg_minibuf[2] = '\0';
- strcat(msg_buf, msg_minibuf);
- /// colour_code = 0;
- }
- /* Process the string... */
- while (text_len < line_len) {
- switch (msg[msg_scan]) {
- case '\0': /* String ends! */
- text_len = line_len;
- continue;
- case '\377': /* Colour code! Text length does not increase. */
- if (!no_colour_code) {
- /* broken \377 at the end of the text? ignore */
- if (color_char_to_attr(msg[msg_scan + 1]) == -1) {
- msg_scan++;
- continue;
- }
- /* Capture double \377 which stand for a normal { char instead of a colour code: */
- if (msg[msg_scan + 1] != '\377') {
- msg_minibuf[0] = msg[msg_scan];
- msg_scan++;
- /* needed for new '\377-' feature in multi-line messages: resolve it to actual colour */
- if (msg[msg_scan] == '-') {
- msg[msg_scan] = colour_code = first_colour_code; //prev_colour_code
- } else {
- prev_colour_code = colour_code = msg[msg_scan];
- if (!first_colour_code_set) {
- first_colour_code_set = TRUE;
- first_colour_code = colour_code;
- }
- }
- msg_minibuf[1] = colour_code;
- msg_scan++;
- msg_minibuf[2] = '\0';
- strcat(msg_buf, msg_minibuf);
- break;
- }
- no_colour_code = TRUE;
- } else no_colour_code = FALSE;
- /* fall through if it's a '{' character */
- default: /* Text length increases by another character.. */
- /* Depending on message type, remember to tab the following
- lines accordingly to make it look better ^^
- depending on the first character of this line. */
- if (first_character) {
- switch (msg[msg_scan]) {
- case '*': tab_spacer = 2; break; /* Kill message */
- case '[': /* Chat message */
- #if 0
- tab_spacer = 1;
- #else
- {
- const char *bracket = strchr(&msg[msg_scan], ']');
- if (bracket) {
- const char *ptr = &msg[msg_scan];
- /* Pad lines according to how long the name is - mikaelh */
- tab_spacer = bracket - &msg[msg_scan] + 2;
- /* Ignore space reserved for colour codes:
- Guild chat has coloured [ ] brackets. - C. Blue */
- while ((ptr = strchr(ptr, '\377')) && ptr < bracket) {
- ptr++;
- tab_spacer -= 2; /* colour code consists of two chars
- (we can guarantee that here, since the server
- generated this colour code) */
- }
- /* Hack: multiline /me emotes */
- if (tab_spacer > 70) tab_spacer = 1;
- /* Paranoia */
- if (tab_spacer < 1) tab_spacer = 1;
- if (tab_spacer > 30) tab_spacer = 30;
- } else {
- /* No ']' */
- tab_spacer = 1;
- }
- }
- #endif
- break;
- default: tab_spacer = 1;
- }
- }
- /* remember first actual chat colour (guild chat changes
- colour a few times for [..] brackets and name).
- This is for {- etc feature.
- However, if there is no new colour specified before
- beginning of chat text then use the one we had, or {-
- wouldn't work correctly in private chat anymore. - C. Blue */
- if (msg[msg_scan] == ']' &&
- #if 0 /* this is wrong, because the colour code COULD already be from \\a feature! */
- ((msg[msg_scan + 1] == ' ' && msg[msg_scan + 2] == '\377') ||
- #endif
- msg[msg_scan + 1] == '\377') {
- first_colour_code_set = FALSE;
- }
- /* Process text.. */
- first_character = FALSE;
- msg_minibuf[0] = msg[msg_scan];
- msg_minibuf[1] = '\0';
- strcat(msg_buf, msg_minibuf);
- msg_scan++;
- text_len++;
- /* Avoid cutting words in two */
- if ((text_len == line_len) && (msg[msg_scan] != '\0')
- && (
- (msg[msg_scan - 1] >= 'A' && msg[msg_scan - 1] <= 'Z') ||
- (msg[msg_scan - 1] >= 'a' && msg[msg_scan - 1] <= 'z') ||
- (msg[msg_scan - 1] >= '0' && msg[msg_scan - 1] <= '9') ||
- msg[msg_scan - 1] == '(' ||
- msg[msg_scan - 1] == '[' ||
- msg[msg_scan - 1] == '{' ||
- #if 0
- msg[msg_scan - 1] == ')' ||
- msg[msg_scan - 1] == ']' ||
- msg[msg_scan - 1] == '}' ||
- #endif
- /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
- msg[msg_scan - 1] == '+' || msg[msg_scan - 1] == '-' ||
- /* Don't break colour codes */
- msg[msg_scan - 1] == '\377'
- ) && (
- (msg[msg_scan] >= 'A' && msg[msg_scan] <= 'Z') ||
- (msg[msg_scan] >= 'a' && msg[msg_scan] <= 'z') ||
- (msg[msg_scan] >= '0' && msg[msg_scan] <= '9') ||
- #if 0
- msg[msg_scan] == '(' ||
- msg[msg_scan] == '[' ||
- msg[msg_scan] == '{' ||
- #endif
- msg[msg_scan] == ')' ||
- msg[msg_scan] == ']' ||
- msg[msg_scan] == '}' ||
- /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
- msg[msg_scan] == '+' || msg[msg_scan] == '-' ||
- /* interpunction at the end of a sentence */
- msg[msg_scan] == '.' || msg[msg_scan] == ',' ||
- msg[msg_scan] == ';' || msg[msg_scan] == ':' ||
- msg[msg_scan] == '!' || msg[msg_scan] == '?' ||
- /* Don't break colour codes */
- msg[msg_scan] == '\377'
- )) {
- space_scan = msg_scan;
- do {
- space_scan--;
- } while (((msg[space_scan - 1] >= 'A' && msg[space_scan - 1] <= 'Z') ||
- (msg[space_scan - 1] >= 'a' && msg[space_scan - 1] <= 'z') ||
- (msg[space_scan - 1] >= '0' && msg[space_scan - 1] <= '9') ||
- #if 0
- msg[space_scan - 1] == ')' ||
- msg[space_scan - 1] == ']' ||
- msg[space_scan - 1] == '}' ||
- #endif
- msg[space_scan - 1] == '(' ||
- msg[space_scan - 1] == '[' ||
- msg[space_scan - 1] == '{' ||
- /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
- msg[space_scan - 1] == '+' || msg[space_scan - 1] == '-' ||
- /* pasting flags to chat ("SLAY_EVIL") */
- msg[space_scan - 1] == '_' ||
- msg[space_scan - 1] == '\377'
- ) && space_scan > 0);
- /* Simply cut words that are very long - mikaelh */
- if (msg_scan - space_scan > 36) {
- space_scan = msg_scan;
- }
- if (space_scan) {
- msg_buf[strlen(msg_buf) - msg_scan + space_scan] = '\0';
- msg_scan = space_scan;
- }
- }
- }
- }
- Send_message(Ind, format("%s%s%s",
- client_chat ? "\375" : (client_all ? "\374" : ""),
- client_ctrlo ? "\376" : "",
- msg_buf));
- /* hack: avoid trailing space in the next sub-line */
- if (msg[msg_scan] == ' ') msg_scan++;
- }
- if (msg == NULL) Send_message(Ind, msg);
- return;
- #endif // enable line breaks?
- Send_message(Ind, format("%s%s%s",
- client_chat ? "\375" : (client_all ? "\374" : ""),
- client_ctrlo ? "\376" : "",
- msg));
- }
- void msg_broadcast(int Ind, cptr msg)
- {
- int i;
-
- /* Tell every player */
- for (i = 1; i <= NumPlayers; i++)
- {
- /* Skip disconnected players */
- if (Players[i]->conn == NOT_CONNECTED)
- continue;
-
- /* Skip the specified player */
- if (i == Ind)
- continue;
-
- /* Tell this one */
- msg_print(i, msg);
- }
- }
- void msg_admins(int Ind, cptr msg)
- {
- int i;
-
- /* Tell every player */
- for (i = 1; i <= NumPlayers; i++)
- {
- /* Skip disconnected players */
- if (Players[i]->conn == NOT_CONNECTED)
- continue;
-
- /* Skip the specified player */
- if (i == Ind)
- continue;
-
- /* Skip non-admins */
- if (!is_admin(Players[i]))
- continue;
-
- /* Tell this one */
- msg_print(i, msg);
- }
- }
- void msg_broadcast_format(int Ind, cptr fmt, ...)
- {
- // int i;
-
- va_list vp;
- char buf[1024];
- /* Begin the Varargs Stuff */
- va_start(vp, fmt);
-
- /* Format the args, save the length */
- (void)vstrnfmt(buf, 1024, fmt, vp);
- /* End the Varargs Stuff */
- va_end(vp);
- msg_broadcast(Ind, buf);
- }
- /* Send a formatted message only to admin chars. -Jir- */
- void msg_admin(cptr fmt, ...)
- //void msg_admin(int Ind, cptr fmt, ...)
- {
- int i;
- player_type *p_ptr;
-
- va_list vp;
- char buf[1024];
- /* Begin the Varargs Stuff */
- va_start(vp, fmt);
-
- /* Format the args, save the length */
- (void)vstrnfmt(buf, 1024, fmt, vp);
- /* End the Varargs Stuff */
- va_end(vp);
- /* Tell every admin */
- for (i = 1; i <= NumPlayers; i++)
- {
- p_ptr = Players[i];
- /* Skip disconnected players */
- if (p_ptr->conn == NOT_CONNECTED)
- continue;
-
- /* Tell Mama */
- if (is_admin(p_ptr))
- msg_print(i, buf);
- }
- }
- /*
- * Display a formatted message, using "vstrnfmt()" and "msg_print()".
- */
- void msg_format(int Ind, cptr fmt, ...)
- {
- va_list vp;
- char buf[1024];
- /* Begin the Varargs Stuff */
- va_start(vp, fmt);
-
- /* Format the args, save the length */
- (void)vstrnfmt(buf, 1024, fmt, vp);
- /* End the Varargs Stuff */
- va_end(vp);
- /* Display */
- msg_print(Ind, buf);
- }
- /*
- * Send a message to ever…
Large files files are truncated, but you can click here to view the full file