PageRenderTime 68ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 1ms

/tomenet-4.5.3a/src/server/util.c

https://bitbucket.org/jpuertos/atomic
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

  1. /* $Id$ */
  2. /* File: util.c */
  3. /* Purpose: Angband utilities -BEN- */
  4. #define SERVER
  5. #include "angband.h"
  6. #ifdef TOMENET_WORLDS
  7. #include "../world/world.h"
  8. #endif
  9. #ifdef MINGW
  10. /* For gettimeofday */
  11. #include <sys/time.h>
  12. #endif
  13. static void console_talk_aux(char *message);
  14. //static int name_lookup_loose_quiet(int Ind, cptr name, u16b party);
  15. #ifndef HAS_MEMSET
  16. /*
  17. * For those systems that don't have "memset()"
  18. *
  19. * Set the value of each of 'n' bytes starting at 's' to 'c', return 's'
  20. * If 'n' is negative, you will erase a whole lot of memory.
  21. */
  22. char *memset(char *s, int c, huge n)
  23. {
  24. char *t;
  25. for (t = s; n--; ) *t++ = c;
  26. return (s);
  27. }
  28. #endif
  29. #ifndef HAS_STRICMP
  30. /*
  31. * For those systems that don't have "stricmp()"
  32. *
  33. * Compare the two strings "a" and "b" ala "strcmp()" ignoring case.
  34. */
  35. int stricmp(cptr a, cptr b)
  36. {
  37. cptr s1, s2;
  38. char z1, z2;
  39. /* Scan the strings */
  40. for (s1 = a, s2 = b; TRUE; s1++, s2++)
  41. {
  42. z1 = FORCEUPPER(*s1);
  43. z2 = FORCEUPPER(*s2);
  44. if (z1 < z2) return (-1);
  45. if (z1 > z2) return (1);
  46. if (!z1) return (0);
  47. }
  48. }
  49. #endif
  50. bool in_banlist(char *addr){
  51. struct ip_ban *ptr;
  52. for(ptr=banlist; ptr!=(struct ip_ban*)NULL; ptr=ptr->next){
  53. if(!strcmp(addr, ptr->ip)) return(TRUE);
  54. }
  55. return(FALSE);
  56. }
  57. void check_banlist(){
  58. struct ip_ban *ptr, *new, *old=(struct ip_ban*)NULL;
  59. ptr=banlist;
  60. while(ptr!=(struct ip_ban*)NULL){
  61. if(ptr->time){
  62. if(!(--ptr->time)){
  63. s_printf("Unbanning connections from %s\n", ptr->ip);
  64. if(!old){
  65. banlist=ptr->next;
  66. new=banlist;
  67. }
  68. else{
  69. old->next=ptr->next;
  70. new=old->next;
  71. }
  72. free(ptr);
  73. ptr=new;
  74. continue;
  75. }
  76. }
  77. ptr=ptr->next;
  78. }
  79. }
  80. #ifdef SET_UID
  81. # ifndef HAS_USLEEP
  82. /*
  83. * For those systems that don't have "usleep()" but need it.
  84. *
  85. * Fake "usleep()" function grabbed from the inl netrek server -cba
  86. */
  87. static int usleep(huge microSeconds)
  88. {
  89. struct timeval Timer;
  90. int nfds = 0;
  91. #ifdef FD_SET
  92. fd_set *no_fds = NULL;
  93. #else
  94. int *no_fds = NULL;
  95. #endif
  96. /* Was: int readfds, writefds, exceptfds; */
  97. /* Was: readfds = writefds = exceptfds = 0; */
  98. /* Paranoia -- No excessive sleeping */
  99. if (microSeconds > 4000000L) core("Illegal usleep() call");
  100. /* Wait for it */
  101. Timer.tv_sec = (microSeconds / 1000000L);
  102. Timer.tv_usec = (microSeconds % 1000000L);
  103. /* Wait for it */
  104. if (select(nfds, no_fds, no_fds, no_fds, &Timer) < 0)
  105. {
  106. /* Hack -- ignore interrupts */
  107. if (errno != EINTR) return -1;
  108. }
  109. /* Success */
  110. return 0;
  111. }
  112. # endif
  113. /*
  114. * Hack -- External functions
  115. */
  116. extern struct passwd *getpwuid();
  117. extern struct passwd *getpwnam();
  118. /*
  119. * Find a default user name from the system.
  120. */
  121. void user_name(char *buf, int id)
  122. {
  123. struct passwd *pw;
  124. /* Look up the user name */
  125. if ((pw = getpwuid(id)))
  126. {
  127. (void)strcpy(buf, pw->pw_name);
  128. buf[16] = '\0';
  129. #ifdef CAPITALIZE_USER_NAME
  130. /* Hack -- capitalize the user name */
  131. if (islower(buf[0])) buf[0] = toupper(buf[0]);
  132. #endif
  133. return;
  134. }
  135. /* Oops. Hack -- default to "PLAYER" */
  136. strcpy(buf, "PLAYER");
  137. }
  138. #endif /* SET_UID */
  139. /*
  140. * The concept of the "file" routines below (and elsewhere) is that all
  141. * file handling should be done using as few routines as possible, since
  142. * every machine is slightly different, but these routines always have the
  143. * same semantics.
  144. *
  145. * In fact, perhaps we should use the "path_parse()" routine below to convert
  146. * from "canonical" filenames (optional leading tilde's, internal wildcards,
  147. * slash as the path seperator, etc) to "system" filenames (no special symbols,
  148. * system-specific path seperator, etc). This would allow the program itself
  149. * to assume that all filenames are "Unix" filenames, and explicitly "extract"
  150. * such filenames if needed (by "path_parse()", or perhaps "path_canon()").
  151. *
  152. * Note that "path_temp" should probably return a "canonical" filename.
  153. *
  154. * Note that "my_fopen()" and "my_open()" and "my_make()" and "my_kill()"
  155. * and "my_move()" and "my_copy()" should all take "canonical" filenames.
  156. *
  157. * Note that "canonical" filenames use a leading "slash" to indicate an absolute
  158. * path, and a leading "tilde" to indicate a special directory, and default to a
  159. * relative path, but MSDOS uses a leading "drivename plus colon" to indicate the
  160. * use of a "special drive", and then the rest of the path is parsed "normally",
  161. * and MACINTOSH uses a leading colon to indicate a relative path, and an embedded
  162. * colon to indicate a "drive plus absolute path", and finally defaults to a file
  163. * in the current working directory, which may or may not be defined.
  164. *
  165. * We should probably parse a leading "~~/" as referring to "ANGBAND_DIR". (?)
  166. */
  167. #ifdef ACORN
  168. /*
  169. * Most of the "file" routines for "ACORN" should be in "main-acn.c"
  170. */
  171. #else /* ACORN */
  172. #ifdef SET_UID
  173. /*
  174. * Extract a "parsed" path from an initial filename
  175. * Normally, we simply copy the filename into the buffer
  176. * But leading tilde symbols must be handled in a special way
  177. * Replace "~user/" by the home directory of the user named "user"
  178. * Replace "~/" by the home directory of the current user
  179. */
  180. errr path_parse(char *buf, int max, cptr file)
  181. {
  182. cptr u, s;
  183. struct passwd *pw;
  184. char user[128];
  185. /* Assume no result */
  186. buf[0] = '\0';
  187. /* No file? */
  188. if (!file) return (-1);
  189. /* File needs no parsing */
  190. if (file[0] != '~')
  191. {
  192. strcpy(buf, file);
  193. return (0);
  194. }
  195. /* Point at the user */
  196. u = file+1;
  197. /* Look for non-user portion of the file */
  198. s = strstr(u, PATH_SEP);
  199. /* Hack -- no long user names */
  200. if (s && (s >= u + sizeof(user))) return (1);
  201. /* Extract a user name */
  202. if (s)
  203. {
  204. int i;
  205. for (i = 0; u < s; ++i) user[i] = *u++;
  206. user[i] = '\0';
  207. u = user;
  208. }
  209. /* Look up the "current" user */
  210. if (u[0] == '\0') u = getlogin();
  211. /* Look up a user (or "current" user) */
  212. if (u) pw = getpwnam(u);
  213. else pw = getpwuid(getuid());
  214. /* Nothing found? */
  215. if (!pw) return (1);
  216. /* Make use of the info */
  217. (void)strcpy(buf, pw->pw_dir);
  218. /* Append the rest of the filename, if any */
  219. if (s) (void)strcat(buf, s);
  220. /* Success */
  221. return (0);
  222. }
  223. #else /* SET_UID */
  224. /*
  225. * Extract a "parsed" path from an initial filename
  226. *
  227. * This requires no special processing on simple machines,
  228. * except for verifying the size of the filename.
  229. */
  230. errr path_parse(char *buf, int max, cptr file)
  231. {
  232. /* Accept the filename */
  233. strnfmt(buf, max, "%s", file);
  234. /* Success */
  235. return (0);
  236. }
  237. #endif /* SET_UID */
  238. /*
  239. * Hack -- acquire a "temporary" file name if possible
  240. *
  241. * This filename is always in "system-specific" form.
  242. */
  243. errr path_temp(char *buf, int max)
  244. {
  245. #ifdef WINDOWS
  246. static u32b tmp_counter;
  247. static char valid_characters[] =
  248. "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  249. char rand_ext[4];
  250. rand_ext[0] = valid_characters[rand_int(sizeof (valid_characters))];
  251. rand_ext[1] = valid_characters[rand_int(sizeof (valid_characters))];
  252. rand_ext[2] = valid_characters[rand_int(sizeof (valid_characters))];
  253. rand_ext[3] = '\0';
  254. strnfmt(buf, max, "%s/server_%ud.%s", ANGBAND_DIR_DATA, tmp_counter, rand_ext);
  255. tmp_counter++;
  256. #else
  257. cptr s;
  258. /* Temp file */
  259. s = tmpnam(NULL);
  260. /* Oops */
  261. if (!s) return (-1);
  262. /* Format to length */
  263. strnfmt(buf, max, "%s", s);
  264. #endif
  265. /* Success */
  266. return (0);
  267. }
  268. /*
  269. * Hack -- replacement for "fopen()"
  270. */
  271. FILE *my_fopen(cptr file, cptr mode)
  272. {
  273. char buf[1024];
  274. /* Hack -- Try to parse the path */
  275. if (path_parse(buf, 1024, file)) return (NULL);
  276. /* Attempt to fopen the file anyway */
  277. return (fopen(buf, mode));
  278. }
  279. /*
  280. * Hack -- replacement for "fclose()"
  281. */
  282. errr my_fclose(FILE *fff)
  283. {
  284. /* Require a file */
  285. if (!fff) return (-1);
  286. /* Close, check for error */
  287. if (fclose(fff) == EOF) return (1);
  288. /* Success */
  289. return (0);
  290. }
  291. #endif /* ACORN */
  292. /*
  293. * Hack -- replacement for "fgets()"
  294. *
  295. * Read a string, without a newline, to a file
  296. *
  297. * Process tabs, strip internal non-printables
  298. */
  299. errr my_fgets(FILE *fff, char *buf, huge n, bool conv)
  300. {
  301. huge i = 0;
  302. char *s;
  303. char tmp[1024];
  304. /* Read a line */
  305. if (fgets(tmp, 1024, fff))
  306. {
  307. /* Convert weirdness */
  308. for (s = tmp; *s; s++)
  309. {
  310. /* Handle newline */
  311. if (*s == '\n')
  312. {
  313. /* Terminate */
  314. buf[i] = '\0';
  315. /* Success */
  316. return (0);
  317. }
  318. /* Handle tabs */
  319. else if (*s == '\t')
  320. {
  321. /* Hack -- require room */
  322. if (i + 8 >= n) break;
  323. /* Append a space */
  324. buf[i++] = ' ';
  325. /* Append some more spaces */
  326. while (!(i % 8)) buf[i++] = ' ';
  327. }
  328. /* Handle printables */
  329. else if (isprint(*s) || *s=='\377')
  330. {
  331. /* easier to edit perma files */
  332. if(conv && *s=='{' && *(s+1)!='{')
  333. *s='\377';
  334. /* Copy */
  335. buf[i++] = *s;
  336. /* Check length */
  337. if (i >= n) break;
  338. }
  339. }
  340. }
  341. /* Nothing */
  342. buf[0] = '\0';
  343. /* Failure */
  344. return (1);
  345. }
  346. /*
  347. * Hack -- replacement for "fputs()"
  348. *
  349. * Dump a string, plus a newline, to a file
  350. *
  351. * XXX XXX XXX Process internal weirdness?
  352. */
  353. errr my_fputs(FILE *fff, cptr buf, huge n)
  354. {
  355. /* XXX XXX */
  356. n = n ? n : 0;
  357. /* Dump, ignore errors */
  358. (void)fprintf(fff, "%s\n", buf);
  359. /* Success */
  360. return (0);
  361. }
  362. #ifdef ACORN
  363. /*
  364. * Most of the "file" routines for "ACORN" should be in "main-acn.c"
  365. *
  366. * Many of them can be rewritten now that only "fd_open()" and "fd_make()"
  367. * and "my_fopen()" should ever create files.
  368. */
  369. #else /* ACORN */
  370. /*
  371. * Code Warrior is a little weird about some functions
  372. */
  373. #ifdef BEN_HACK
  374. extern int open(const char *, int, ...);
  375. extern int close(int);
  376. extern int read(int, void *, unsigned int);
  377. extern int write(int, const void *, unsigned int);
  378. extern long lseek(int, long, int);
  379. #endif /* BEN_HACK */
  380. /*
  381. * The Macintosh is a little bit brain-dead sometimes
  382. */
  383. #ifdef MACINTOSH
  384. # define open(N,F,M) open((char*)(N),F)
  385. # define write(F,B,S) write(F,(char*)(B),S)
  386. #endif /* MACINTOSH */
  387. /*
  388. * Several systems have no "O_BINARY" flag
  389. */
  390. #ifndef O_BINARY
  391. # define O_BINARY 0
  392. #endif /* O_BINARY */
  393. /*
  394. * Hack -- attempt to delete a file
  395. */
  396. errr fd_kill(cptr file)
  397. {
  398. char buf[1024];
  399. /* Hack -- Try to parse the path */
  400. if (path_parse(buf, 1024, file)) return (-1);
  401. /* Remove */
  402. (void)remove(buf);
  403. /* XXX XXX XXX */
  404. return (0);
  405. }
  406. /*
  407. * Hack -- attempt to move a file
  408. */
  409. errr fd_move(cptr file, cptr what)
  410. {
  411. char buf[1024];
  412. char aux[1024];
  413. /* Hack -- Try to parse the path */
  414. if (path_parse(buf, 1024, file)) return (-1);
  415. /* Hack -- Try to parse the path */
  416. if (path_parse(aux, 1024, what)) return (-1);
  417. /* Rename */
  418. (void)rename(buf, aux);
  419. /* XXX XXX XXX */
  420. return (0);
  421. }
  422. /*
  423. * Hack -- attempt to copy a file
  424. */
  425. errr fd_copy(cptr file, cptr what)
  426. {
  427. char buf[1024];
  428. char aux[1024];
  429. /* Hack -- Try to parse the path */
  430. if (path_parse(buf, 1024, file)) return (-1);
  431. /* Hack -- Try to parse the path */
  432. if (path_parse(aux, 1024, what)) return (-1);
  433. /* Copy XXX XXX XXX */
  434. /* (void)rename(buf, aux); */
  435. /* XXX XXX XXX */
  436. return (1);
  437. }
  438. /*
  439. * Hack -- attempt to open a file descriptor (create file)
  440. *
  441. * This function should fail if the file already exists
  442. *
  443. * Note that we assume that the file should be "binary"
  444. *
  445. * XXX XXX XXX The horrible "BEN_HACK" code is for compiling under
  446. * the CodeWarrior compiler, in which case, for some reason, none
  447. * of the "O_*" flags are defined, and we must fake the definition
  448. * of "O_RDONLY", "O_WRONLY", and "O_RDWR" in "A-win-h", and then
  449. * we must simulate the effect of the proper "open()" call below.
  450. */
  451. int fd_make(cptr file, int mode)
  452. {
  453. char buf[1024];
  454. /* Hack -- Try to parse the path */
  455. if (path_parse(buf, 1024, file)) return (-1);
  456. #ifdef BEN_HACK
  457. /* Check for existance */
  458. /* if (fd_close(fd_open(file, O_RDONLY | O_BINARY))) return (1); */
  459. /* Mega-Hack -- Create the file */
  460. (void)my_fclose(my_fopen(file, "wb"));
  461. /* Re-open the file for writing */
  462. return (open(buf, O_WRONLY | O_BINARY, mode));
  463. #else /* BEN_HACK */
  464. /* Create the file, fail if exists, write-only, binary */
  465. return (open(buf, O_CREAT | O_EXCL | O_WRONLY | O_BINARY, mode));
  466. #endif /* BEN_HACK */
  467. }
  468. /*
  469. * Hack -- attempt to open a file descriptor (existing file)
  470. *
  471. * Note that we assume that the file should be "binary"
  472. */
  473. int fd_open(cptr file, int flags)
  474. {
  475. char buf[1024];
  476. /* Hack -- Try to parse the path */
  477. if (path_parse(buf, 1024, file)) return (-1);
  478. /* Attempt to open the file */
  479. return (open(buf, flags | O_BINARY, 0));
  480. }
  481. /*
  482. * Hack -- attempt to lock a file descriptor
  483. *
  484. * Legal lock types -- F_UNLCK, F_RDLCK, F_WRLCK
  485. */
  486. errr fd_lock(int fd, int what)
  487. {
  488. /* XXX XXX */
  489. what = what ? what : 0;
  490. /* Verify the fd */
  491. if (fd < 0) return (-1);
  492. #ifdef SET_UID
  493. # ifdef USG
  494. /* Un-Lock */
  495. if (what == F_UNLCK)
  496. {
  497. /* Unlock it, Ignore errors */
  498. lockf(fd, F_ULOCK, 0);
  499. }
  500. /* Lock */
  501. else
  502. {
  503. /* Lock the score file */
  504. if (lockf(fd, F_LOCK, 0) != 0) return (1);
  505. }
  506. #else
  507. /* Un-Lock */
  508. if (what == F_UNLCK)
  509. {
  510. /* Unlock it, Ignore errors */
  511. (void)flock(fd, LOCK_UN);
  512. }
  513. /* Lock */
  514. else
  515. {
  516. /* Lock the score file */
  517. if (flock(fd, LOCK_EX) != 0) return (1);
  518. }
  519. # endif
  520. #endif
  521. /* Success */
  522. return (0);
  523. }
  524. /*
  525. * Hack -- attempt to seek on a file descriptor
  526. */
  527. errr fd_seek(int fd, huge n)
  528. {
  529. huge p;
  530. /* Verify fd */
  531. if (fd < 0) return (-1);
  532. /* Seek to the given position */
  533. p = lseek(fd, n, SEEK_SET);
  534. /* Failure */
  535. if (p == (huge) -1) return (1);
  536. /* Failure */
  537. if (p != n) return (1);
  538. /* Success */
  539. return (0);
  540. }
  541. /*
  542. * Hack -- attempt to read data from a file descriptor
  543. */
  544. errr fd_read(int fd, char *buf, huge n)
  545. {
  546. /* Verify the fd */
  547. if (fd < 0) return (-1);
  548. #ifndef SET_UID
  549. /* Read pieces */
  550. while (n >= 16384)
  551. {
  552. /* Read a piece */
  553. if (read(fd, buf, 16384) != 16384) return (1);
  554. /* Shorten the task */
  555. buf += 16384;
  556. /* Shorten the task */
  557. n -= 16384;
  558. }
  559. #endif
  560. /* Read the final piece */
  561. if ((huge) read(fd, buf, n) != n) return (1);
  562. /* Success */
  563. return (0);
  564. }
  565. /*
  566. * Hack -- Attempt to write data to a file descriptor
  567. */
  568. errr fd_write(int fd, cptr buf, huge n)
  569. {
  570. /* Verify the fd */
  571. if (fd < 0) return (-1);
  572. #ifndef SET_UID
  573. /* Write pieces */
  574. while (n >= 16384)
  575. {
  576. /* Write a piece */
  577. if (write(fd, buf, 16384) != 16384) return (1);
  578. /* Shorten the task */
  579. buf += 16384;
  580. /* Shorten the task */
  581. n -= 16384;
  582. }
  583. #endif
  584. /* Write the final piece */
  585. if ((huge) write(fd, buf, n) != n) return (1);
  586. /* Success */
  587. return (0);
  588. }
  589. /*
  590. * Hack -- attempt to close a file descriptor
  591. */
  592. errr fd_close(int fd)
  593. {
  594. /* Verify the fd */
  595. if (fd < 0) return (-1);
  596. /* Close */
  597. (void)close(fd);
  598. /* XXX XXX XXX */
  599. return (0);
  600. }
  601. #endif /* ACORN */
  602. /*
  603. * Convert a decimal to a single digit octal number
  604. */
  605. static char octify(uint i)
  606. {
  607. return (hexsym[i%8]);
  608. }
  609. /*
  610. * Convert a decimal to a single digit hex number
  611. */
  612. static char hexify(uint i)
  613. {
  614. return (hexsym[i%16]);
  615. }
  616. /*
  617. * Convert a octal-digit into a decimal
  618. */
  619. static int deoct(char c)
  620. {
  621. if (isdigit(c)) return (D2I(c));
  622. return (0);
  623. }
  624. /*
  625. * Convert a hexidecimal-digit into a decimal
  626. */
  627. static int dehex(char c)
  628. {
  629. if (isdigit(c)) return (D2I(c));
  630. if (islower(c)) return (A2I(c) + 10);
  631. if (isupper(c)) return (A2I(tolower(c)) + 10);
  632. return (0);
  633. }
  634. /*
  635. * Hack -- convert a printable string into real ascii
  636. *
  637. * I have no clue if this function correctly handles, for example,
  638. * parsing "\xFF" into a (signed) char. Whoever thought of making
  639. * the "sign" of a "char" undefined is a complete moron. Oh well.
  640. */
  641. void text_to_ascii(char *buf, cptr str)
  642. {
  643. char *s = buf;
  644. /* Analyze the "ascii" string */
  645. while (*str)
  646. {
  647. /* Backslash codes */
  648. if (*str == '\\')
  649. {
  650. /* Skip the backslash */
  651. str++;
  652. /* Hex-mode XXX */
  653. if (*str == 'x')
  654. {
  655. *s = 16 * dehex(*++str);
  656. *s++ += dehex(*++str);
  657. }
  658. /* Hack -- simple way to specify "backslash" */
  659. else if (*str == '\\')
  660. {
  661. *s++ = '\\';
  662. }
  663. /* Hack -- simple way to specify "caret" */
  664. else if (*str == '^')
  665. {
  666. *s++ = '^';
  667. }
  668. /* Hack -- simple way to specify "space" */
  669. else if (*str == 's')
  670. {
  671. *s++ = ' ';
  672. }
  673. /* Hack -- simple way to specify Escape */
  674. else if (*str == 'e')
  675. {
  676. *s++ = ESCAPE;
  677. }
  678. /* Backspace */
  679. else if (*str == 'b')
  680. {
  681. *s++ = '\b';
  682. }
  683. /* Newline */
  684. else if (*str == 'n')
  685. {
  686. *s++ = '\n';
  687. }
  688. /* Return */
  689. else if (*str == 'r')
  690. {
  691. *s++ = '\r';
  692. }
  693. /* Tab */
  694. else if (*str == 't')
  695. {
  696. *s++ = '\t';
  697. }
  698. /* Octal-mode */
  699. else if (*str == '0')
  700. {
  701. *s = 8 * deoct(*++str);
  702. *s++ += deoct(*++str);
  703. }
  704. /* Octal-mode */
  705. else if (*str == '1')
  706. {
  707. *s = 64 + 8 * deoct(*++str);
  708. *s++ += deoct(*++str);
  709. }
  710. /* Octal-mode */
  711. else if (*str == '2')
  712. {
  713. *s = 64 * 2 + 8 * deoct(*++str);
  714. *s++ += deoct(*++str);
  715. }
  716. /* Octal-mode */
  717. else if (*str == '3')
  718. {
  719. *s = 64 * 3 + 8 * deoct(*++str);
  720. *s++ += deoct(*++str);
  721. }
  722. /* Skip the final char */
  723. str++;
  724. }
  725. /* Normal Control codes */
  726. else if (*str == '^')
  727. {
  728. str++;
  729. *s++ = (*str++ & 037);
  730. }
  731. /* Normal chars */
  732. else
  733. {
  734. *s++ = *str++;
  735. }
  736. }
  737. /* Terminate */
  738. *s = '\0';
  739. }
  740. /*
  741. * Hack -- convert a string into a printable form
  742. */
  743. void ascii_to_text(char *buf, cptr str)
  744. {
  745. char *s = buf;
  746. /* Analyze the "ascii" string */
  747. while (*str)
  748. {
  749. byte i = (byte)(*str++);
  750. if (i == ESCAPE)
  751. {
  752. *s++ = '\\';
  753. *s++ = 'e';
  754. }
  755. else if (i == ' ')
  756. {
  757. *s++ = '\\';
  758. *s++ = 's';
  759. }
  760. else if (i == '\b')
  761. {
  762. *s++ = '\\';
  763. *s++ = 'b';
  764. }
  765. else if (i == '\t')
  766. {
  767. *s++ = '\\';
  768. *s++ = 't';
  769. }
  770. else if (i == '\n')
  771. {
  772. *s++ = '\\';
  773. *s++ = 'n';
  774. }
  775. else if (i == '\r')
  776. {
  777. *s++ = '\\';
  778. *s++ = 'r';
  779. }
  780. else if (i == '^')
  781. {
  782. *s++ = '\\';
  783. *s++ = '^';
  784. }
  785. else if (i == '\\')
  786. {
  787. *s++ = '\\';
  788. *s++ = '\\';
  789. }
  790. else if (i < 32)
  791. {
  792. *s++ = '^';
  793. *s++ = i + 64;
  794. }
  795. else if (i < 127)
  796. {
  797. *s++ = i;
  798. }
  799. else if (i < 64)
  800. {
  801. *s++ = '\\';
  802. *s++ = '0';
  803. *s++ = octify(i / 8);
  804. *s++ = octify(i % 8);
  805. }
  806. else
  807. {
  808. *s++ = '\\';
  809. *s++ = 'x';
  810. *s++ = hexify(i / 16);
  811. *s++ = hexify(i % 16);
  812. }
  813. }
  814. /* Terminate */
  815. *s = '\0';
  816. }
  817. /*
  818. * Local variable -- we are inside a "control-underscore" sequence
  819. */
  820. /*static bool parse_under = FALSE;*/
  821. /*
  822. * Local variable -- we are inside a "control-backslash" sequence
  823. */
  824. /*static bool parse_slash = FALSE;*/
  825. /*
  826. * Local variable -- we are stripping symbols for a while
  827. */
  828. /*static bool strip_chars = FALSE;*/
  829. /*
  830. * Flush the screen, make a noise
  831. */
  832. void bell(void)
  833. {
  834. }
  835. /*
  836. * Mega-Hack -- Make a (relevant?) sound
  837. */
  838. #ifndef USE_SOUND_2010
  839. void sound(int Ind, int val) {
  840. // Send_sound(Ind, val);
  841. Send_sound(Ind, val, 0, 0, 100, 0);
  842. }
  843. #else
  844. /* 'type' is used client-side, for efficiency options concerning near-simultaneous sounds
  845. 'nearby' means if other players nearby would be able to also hear the sound. - C. Blue */
  846. void sound(int Ind, cptr name, cptr alternative, int type, bool nearby) {
  847. #if 0 /* non-optimized way (causes LUA errors if sound() is called in fire_ball() which is in turn called from LUA - C. Blue */
  848. int val, val2;
  849. val = exec_lua(0, format("return get_sound_index(\"%s\")", name));
  850. if (alternative) {
  851. val2 = exec_lua(0, format("return get_sound_index(\"%s\")", alternative));
  852. } else {
  853. val2 = -1;
  854. }
  855. #else /* optimized way... */
  856. int val = -1, val2 = -1, i, d;
  857. if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
  858. if (!audio_sfx[i][0]) break;
  859. if (!strcmp(audio_sfx[i], name)) {
  860. val = i;
  861. break;
  862. }
  863. }
  864. if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
  865. if (!audio_sfx[i][0]) break;
  866. if (!strcmp(audio_sfx[i], alternative)) {
  867. val2 = i;
  868. break;
  869. }
  870. }
  871. #endif
  872. // if (is_admin(Players[Ind])) s_printf("USE_SOUND_2010: looking up sound %s -> %d.\n", name, val);
  873. if (val == -1) {
  874. if (val2 != -1) {
  875. /* Use the alternative instead */
  876. val = val2;
  877. val2 = -1;
  878. } else {
  879. return;
  880. }
  881. }
  882. /* also send sounds to nearby players, depending on sound or sound type */
  883. if (nearby) {
  884. for (i = 1; i <= NumPlayers; i++) {
  885. if (Players[i]->conn == NOT_CONNECTED) continue;
  886. if (!inarea(&Players[i]->wpos, &Players[Ind]->wpos)) continue;
  887. if (Ind == i) continue;
  888. d = distance(Players[Ind]->py, Players[Ind]->px, Players[i]->py, Players[i]->px);
  889. #if 0
  890. if (d > 10) continue;
  891. if (d == 0) d = 1; //paranoia oO
  892. Send_sound(i, val, val2, type, 100 / d, Players[Ind]->id);
  893. // Send_sound(i, val, val2, type, (6 - d) * 20, Players[Ind]->id); hm or this?
  894. #else
  895. if (d > MAX_SIGHT) continue;
  896. d += 3;
  897. d /= 2;
  898. Send_sound(i, val, val2, type, 100 / d, Players[Ind]->id);
  899. #endif
  900. }
  901. }
  902. Send_sound(Ind, val, val2, type, 100, Players[Ind]->id);
  903. }
  904. /* send sound to player and everyone nearby at full volume, similar to
  905. msg_..._near(), except it also sends to the player himself.
  906. This is used for highly important and *loud* sounds such as 'shriek' - C. Blue */
  907. void sound_near(int Ind, cptr name, cptr alternative, int type) {
  908. int i, d;
  909. for (i = 1; i <= NumPlayers; i++) {
  910. if (Players[i]->conn == NOT_CONNECTED) continue;
  911. if (!inarea(&Players[i]->wpos, &Players[Ind]->wpos)) continue;
  912. /* Can he see this player? */
  913. // if (!(Players[i]->cave_flag[Players[Ind]->py][Players[Ind]->px] & CAVE_VIEW)) continue;
  914. /* within audible range? */
  915. d = distance(Players[Ind]->py, Players[Ind]->px, Players[i]->py, Players[i]->px);
  916. if (d > MAX_SIGHT) continue;
  917. sound(i, name, alternative, type, FALSE);
  918. }
  919. }
  920. /* send sound to all players nearby a certain location, and allow to specify
  921. a player to exclude, same as msg_print_near_site() for messages. - C. Blue */
  922. void sound_near_site(int y, int x, worldpos *wpos, int Ind, cptr name, cptr alternative, int type, bool viewable) {
  923. int i, d;
  924. player_type *p_ptr;
  925. int val = -1, val2 = -1;
  926. if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
  927. if (!audio_sfx[i][0]) break;
  928. if (!strcmp(audio_sfx[i], name)) {
  929. val = i;
  930. break;
  931. }
  932. }
  933. if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
  934. if (!audio_sfx[i][0]) break;
  935. if (!strcmp(audio_sfx[i], alternative)) {
  936. val2 = i;
  937. break;
  938. }
  939. }
  940. if (val == -1) {
  941. if (val2 != -1) {
  942. /* Use the alternative instead */
  943. val = val2;
  944. val2 = -1;
  945. } else {
  946. return;
  947. }
  948. }
  949. /* Check each player */
  950. for (i = 1; i <= NumPlayers; i++) {
  951. /* Check this player */
  952. p_ptr = Players[i];
  953. /* Make sure this player is in the game */
  954. if (p_ptr->conn == NOT_CONNECTED) continue;
  955. /* Skip specified player, if any */
  956. if (i == Ind) continue;
  957. /* Make sure this player is at this depth */
  958. if (!inarea(&p_ptr->wpos, wpos)) continue;
  959. /* Can (s)he see the site? */
  960. if (viewable && !(p_ptr->cave_flag[y][x] & CAVE_VIEW)) continue;
  961. /* within audible range? */
  962. d = distance(y, x, Players[i]->py, Players[i]->px);
  963. /* NOTE: should be consistent with msg_print_near_site() */
  964. if (d > MAX_SIGHT) continue;
  965. #if 0
  966. /* limit for volume calc */
  967. if (d > 20) d = 20;
  968. d += 3;
  969. d /= 3;
  970. Send_sound(i, val, val2, type, 100 / d, 0);
  971. #else
  972. /* limit for volume calc */
  973. Send_sound(i, val, val2, type, 100 - (d * 50) / 11, 0);
  974. #endif
  975. }
  976. }
  977. /* like msg_print_near_monster() just for sounds,
  978. basically same as sound_near_site() - C. Blue */
  979. void sound_near_monster(int m_idx, cptr name, cptr alternative, int type) {
  980. int i, d;
  981. player_type *p_ptr;
  982. cave_type **zcave;
  983. monster_type *m_ptr = &m_list[m_idx];
  984. worldpos *wpos = &m_ptr->wpos;
  985. int val = -1, val2 = -1;
  986. if (!(zcave = getcave(wpos))) return;
  987. if (name) for (i = 0; i < SOUND_MAX_2010; i++) {
  988. if (!audio_sfx[i][0]) break;
  989. if (!strcmp(audio_sfx[i], name)) {
  990. val = i;
  991. break;
  992. }
  993. }
  994. if (alternative) for (i = 0; i < SOUND_MAX_2010; i++) {
  995. if (!audio_sfx[i][0]) break;
  996. if (!strcmp(audio_sfx[i], alternative)) {
  997. val2 = i;
  998. break;
  999. }
  1000. }
  1001. if (val == -1) {
  1002. if (val2 != -1) {
  1003. /* Use the alternative instead */
  1004. val = val2;
  1005. val2 = -1;
  1006. } else {
  1007. return;
  1008. }
  1009. }
  1010. /* Check each player */
  1011. for (i = 1; i <= NumPlayers; i++) {
  1012. /* Check this player */
  1013. p_ptr = Players[i];
  1014. /* Make sure this player is in the game */
  1015. if (p_ptr->conn == NOT_CONNECTED) continue;
  1016. /* Make sure this player is at this depth */
  1017. if (!inarea(&p_ptr->wpos, wpos)) continue;
  1018. /* Skip if not visible */
  1019. // if (!p_ptr->mon_vis[m_idx]) continue;
  1020. /* Can he see this player? */
  1021. // if (!p_ptr->cave_flag[y][x] & CAVE_VIEW) continue;
  1022. /* Can (s)he see the site? */
  1023. // if (!(p_ptr->cave_flag[y][x] & CAVE_VIEW)) continue;
  1024. /* within audible range? */
  1025. d = distance(m_ptr->fy, m_ptr->fx, Players[i]->py, Players[i]->px);
  1026. /* NOTE: should be consistent with msg_print_near_site() */
  1027. if (d > MAX_SIGHT) continue;
  1028. #if 0
  1029. /* limit for volume calc */
  1030. if (d > 20) d = 20;
  1031. d += 3;
  1032. d /= 3;
  1033. Send_sound(i, val, val2, type, 100 / d, 0);
  1034. #else
  1035. /* limit for volume calc */
  1036. Send_sound(i, val, val2, type, 100 - (d * 50) / 11, 0);
  1037. #endif
  1038. }
  1039. }
  1040. /* find correct music for the player based on his current location - C. Blue */
  1041. void handle_music(int Ind) {
  1042. player_type *p_ptr = Players[Ind];
  1043. dun_level *l_ptr = NULL;
  1044. int i = -1, tmus = 0, tmus_inverse = 0;
  1045. cave_type **zcave = getcave(&p_ptr->wpos);
  1046. #ifdef ARCADE_SERVER
  1047. /* Special music for Arcade Server stuff */
  1048. if (p_ptr->wpos.wx == WPOS_ARCADE_X && p_ptr->wpos.wy == WPOS_ARCADE_Y
  1049. // && p_ptr->wpos.wz == WPOS_ARCADE_Z
  1050. ) {
  1051. p_ptr->music_monster = -2;
  1052. if (p_ptr->wpos.wz == 0) Send_music(Ind, 1); /* 'generic town' music instead of Bree default */
  1053. else {
  1054. //47 and 48 are actually pieces used in other arena events
  1055. if (rand_int(2)) Send_music(Ind, 47);
  1056. else Send_music(Ind, 48);
  1057. }
  1058. return;
  1059. }
  1060. #endif
  1061. if (p_ptr->wpos.wz != 0) {
  1062. l_ptr = getfloor(&p_ptr->wpos);
  1063. if (p_ptr->wpos.wz < 0)
  1064. i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].dungeon->type;
  1065. else
  1066. i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].tower->type;
  1067. }
  1068. if (getlevel(&p_ptr->wpos) == 196) {
  1069. //Zu-Aon
  1070. //hack: init music as 'higher priority than boss-specific':
  1071. p_ptr->music_monster = -2;
  1072. Send_music(Ind, 45);
  1073. return;
  1074. } else if ((i != -1) && (l_ptr->flags1 & LF1_NO_GHOST)) {
  1075. //Morgoth
  1076. //hack: init music as 'higher priority than boss-specific':
  1077. p_ptr->music_monster = -2;
  1078. Send_music(Ind, 44);
  1079. return;
  1080. }
  1081. if (getlevel(&p_ptr->wpos) == 200) {
  1082. //hack: init music as 'higher priority than boss-specific':
  1083. p_ptr->music_monster = -2;
  1084. Send_music(Ind, 8); //Valinor
  1085. return;
  1086. } else if (p_ptr->wpos.wx == WPOS_PVPARENA_X &&
  1087. p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z) {
  1088. //hack: init music as 'higher priority than boss-specific':
  1089. p_ptr->music_monster = -2;
  1090. Send_music(Ind, 47); //PvP Arena
  1091. return;
  1092. } else if (ge_special_sector && p_ptr->wpos.wx == WPOS_ARENA_X &&
  1093. p_ptr->wpos.wy == WPOS_ARENA_Y && p_ptr->wpos.wz == WPOS_ARENA_Z) {
  1094. //hack: init music as 'higher priority than boss-specific':
  1095. p_ptr->music_monster = -2;
  1096. Send_music(Ind, 48); //Monster Arena Challenge
  1097. return;
  1098. } else if (sector00separation && p_ptr->wpos.wx == WPOS_HIGHLANDER_X &&
  1099. p_ptr->wpos.wy == WPOS_HIGHLANDER_Y && p_ptr->wpos.wz == WPOS_HIGHLANDER_Z) {
  1100. //hack: init music as 'higher priority than boss-specific':
  1101. p_ptr->music_monster = -2;
  1102. Send_music(Ind, 47); //Highlander Tournament (death match phase)
  1103. return;
  1104. }
  1105. /* No-tele grid: Re-use 'terrifying' bgm for this */
  1106. if (zcave && (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK)) {
  1107. #if 0 /* hack: init music as 'higher priority than boss-specific': */
  1108. p_ptr->music_monster = -2;
  1109. #endif
  1110. Send_music(Ind, 46); //No-Tele vault
  1111. return;
  1112. }
  1113. /* rest of the music has lower priority than already running, boss-specific music */
  1114. if (p_ptr->music_monster != -1) return;
  1115. /* on world surface */
  1116. if (p_ptr->wpos.wz == 0) {
  1117. /* play town music also in its surrounding area of houses, if we're coming from the town? */
  1118. if (istownarea(&p_ptr->wpos, MAX_TOWNAREA)) {
  1119. i = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].town_idx;
  1120. if (night_surface) switch (town[i].type) {
  1121. default:
  1122. case 0: tmus = 49; tmus_inverse = 1; break; //default town
  1123. case 1: tmus = 50; tmus_inverse = 3; break; //Bree
  1124. case 2: tmus = 51; tmus_inverse = 4; break; //Gondo
  1125. case 3: tmus = 52; tmus_inverse = 5; break; //Minas
  1126. case 4: tmus = 53; tmus_inverse = 6; break; //Loth
  1127. case 5: tmus = 54; tmus_inverse = 7; break; //Khaz
  1128. }
  1129. else switch (town[i].type) {
  1130. default:
  1131. case 0: tmus = 1; tmus_inverse = 49; break; //default town
  1132. case 1: tmus = 3; tmus_inverse = 50; break; //Bree
  1133. case 2: tmus = 4; tmus_inverse = 51; break; //Gondo
  1134. case 3: tmus = 5; tmus_inverse = 52; break; //Minas
  1135. case 4: tmus = 6; tmus_inverse = 53; break; //Loth
  1136. case 5: tmus = 7; tmus_inverse = 54; break; //Khaz
  1137. }
  1138. /* now the specialty: If we're coming from elsewhere,
  1139. we only switch to town music when we enter the town.
  1140. If we're coming from the town, however, we keep the
  1141. music while being in its surrounding area of houses. */
  1142. if (istown(&p_ptr->wpos) || p_ptr->music_current == tmus
  1143. /* don't switch from town area music to wild music on day/night change: */
  1144. || p_ptr->music_current == tmus_inverse)
  1145. Send_music(Ind, tmus);
  1146. else if (night_surface) Send_music(Ind, 10);
  1147. else Send_music(Ind, 9);
  1148. return;
  1149. } else {
  1150. if (night_surface) Send_music(Ind, 10);
  1151. else Send_music(Ind, 9);
  1152. return;
  1153. }
  1154. /* in the dungeon */
  1155. } else {
  1156. /* Dungeon towns have their own music to bolster the player's motivation ;) */
  1157. if (isdungeontown(&p_ptr->wpos)) {
  1158. if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) Send_music(Ind, 1); /* 'generic town' music instead, for a change */
  1159. else Send_music(Ind, 2); /* the usual music for this case */
  1160. return;
  1161. }
  1162. /* Floor-specific music (monster/boss-independant)? */
  1163. if ((i != 6) /*not in Nether Realm, really ^^*/
  1164. && (!(d_info[i].flags2 & DF2_NO_DEATH)) /* nor in easy dungeons */
  1165. && !(p_ptr->wpos.wx == WPOS_PVPARENA_X /* and not in pvp-arena */
  1166. && p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z))
  1167. {
  1168. if (p_ptr->distinct_floor_feeling || is_admin(p_ptr)) {
  1169. if (l_ptr->flags2 & LF2_OOD_HI) {
  1170. Send_music(Ind, 46);
  1171. return;
  1172. }
  1173. }
  1174. }
  1175. //we could just look through audio.lua, by querying get_music_name() I guess..
  1176. switch (i) {
  1177. default:
  1178. case 0:
  1179. if (d_info[i].flags2 & DF2_NO_DEATH) Send_music(Ind, 12);
  1180. else if (d_info[i].flags2 & DF2_IRON) Send_music(Ind, 13);
  1181. else if ((d_info[i].flags2 & DF2_HELL) || (d_info[i].flags1 & DF1_FORCE_DOWN)) Send_music(Ind, 14);
  1182. else Send_music(Ind, 11);
  1183. return;
  1184. case 1: Send_music(Ind, 32); return; //Mirkwood
  1185. case 2: Send_music(Ind, 17); return; //Mordor
  1186. case 3: Send_music(Ind, 19); return; //Angband
  1187. case 4: Send_music(Ind, 16); return; //Barrow-Downs
  1188. case 5: Send_music(Ind, 21); return; //Mount Doom
  1189. case 6: Send_music(Ind, 22); return; //Nether Realm
  1190. case 7: Send_music(Ind, 35); return; //Submerged Ruins
  1191. case 8: Send_music(Ind, 26); return; //Halls of Mandos
  1192. case 9: Send_music(Ind, 30); return; //Cirith Ungol
  1193. case 10: Send_music(Ind, 28); return; //The Heart of the Earth
  1194. case 16: Send_music(Ind, 18); return; //The Paths of the Dead
  1195. case 17: Send_music(Ind, 37); return; //The Illusory Castle
  1196. case 18: Send_music(Ind, 39); return; //The Maze
  1197. case 19: Send_music(Ind, 20); return; //The Orc Cave
  1198. case 20: Send_music(Ind, 36); return; //Erebor
  1199. case 21: Send_music(Ind, 27); return; //The Old Forest
  1200. case 22: Send_music(Ind, 29); return; //The Mines of Moria
  1201. case 23: Send_music(Ind, 34); return; //Dol Guldur
  1202. case 24: Send_music(Ind, 31); return; //The Small Water Cave
  1203. case 25: Send_music(Ind, 38); return; //The Sacred Land of Mountains
  1204. case 26: Send_music(Ind, 24); return; //The Land of Rhun
  1205. case 27: Send_music(Ind, 25); return; //The Sandworm Lair
  1206. case 28: Send_music(Ind, 33); return; //Death Fate
  1207. case 29: Send_music(Ind, 23); return; //The Helcaraxe
  1208. case 30: Send_music(Ind, 15); return; //The Training Tower
  1209. }
  1210. }
  1211. /* Shouldn't happen - send default (dungeon) music */
  1212. Send_music(Ind, 0);
  1213. }
  1214. /* generate an item-type specific sound, depending on the action applied to it
  1215. action: 0 = pickup, 1 = drop, 2 = wear/wield, 3 = takeoff, 4 = throw, 5 = destroy */
  1216. void sound_item(int Ind, int tval, int sval, cptr action) {
  1217. char sound_name[30];
  1218. cptr item = NULL;
  1219. /* action hack: re-use sounds! */
  1220. action = "item_";
  1221. /* choose sound */
  1222. if (is_weapon(tval)) switch(tval) {
  1223. case TV_SWORD: item = "sword"; break;
  1224. case TV_BLUNT:
  1225. if (sval == SV_WHIP) item = "whip"; else item = "blunt";
  1226. break;
  1227. case TV_AXE: item = "axe"; break;
  1228. case TV_POLEARM: item = "polearm"; break;
  1229. } else if (is_armour(tval)) {
  1230. if (is_textile_armour(tval, sval))
  1231. item = "armor_light";
  1232. else
  1233. item = "armor_heavy";
  1234. } else switch(tval) {
  1235. /* equippable stuff */
  1236. case TV_LITE: item = "lightsource"; break;
  1237. case TV_RING: item = "ring"; break;
  1238. case TV_AMULET: item = "amulet"; break;
  1239. case TV_TOOL: item = "tool"; break;
  1240. case TV_DIGGING: item = "tool_digger"; break;
  1241. case TV_MSTAFF: item = "magestaff"; break;
  1242. // case TV_BOOMERANG: item = ""; break;
  1243. // case TV_BOW: item = ""; break;
  1244. // case TV_SHOT: item = ""; break;
  1245. // case TV_ARROW: item = ""; break;
  1246. // case TV_BOLT: item = ""; break;
  1247. /* other items */
  1248. // case TV_BOOK: item = "book"; break;
  1249. case TV_SCROLL: case TV_PARCHMENT:
  1250. item = "scroll"; break;
  1251. /* case TV_BOTTLE: item = "potion"; break;
  1252. case TV_POTION: case TV_POTION2: case TV_FLASK:
  1253. item = "potion"; break;*/
  1254. case TV_RUNE:
  1255. item = "rune"; break;
  1256. // case TV_SKELETON: item = ""; break;
  1257. case TV_FIRESTONE: item = "firestone"; break;
  1258. /* case TV_SPIKE: item = ""; break;
  1259. case TV_CHEST: item = ""; break;
  1260. case TV_JUNK: item = ""; break;
  1261. case TV_GAME: item = ""; break;
  1262. case TV_TRAPKIT: item = ""; break;
  1263. case TV_STAFF: item = ""; break;
  1264. case TV_WAND: item = ""; break;
  1265. case TV_ROD: item = ""; break;
  1266. case TV_ROD_MAIN: item = ""; break;
  1267. case TV_FOOD: item = ""; break;
  1268. case TV_KEY: item = ""; break;
  1269. case TV_GOLEM: item = ""; break;
  1270. case TV_SPECIAL: item = ""; break;
  1271. */ }
  1272. /* no sound effect available? */
  1273. if (item == NULL) return;
  1274. /* build sound name from action and item */
  1275. strcpy(sound_name, action);
  1276. strcat(sound_name, item);
  1277. /* off we go */
  1278. sound(Ind, sound_name, NULL, SFX_TYPE_COMMAND, FALSE);
  1279. }
  1280. #endif
  1281. /*
  1282. * We use a global array for all inscriptions to reduce the memory
  1283. * spent maintaining inscriptions. Of course, it is still possible
  1284. * to run out of inscription memory, especially if too many different
  1285. * inscriptions are used, but hopefully this will be rare.
  1286. *
  1287. * We use dynamic string allocation because otherwise it is necessary
  1288. * to pre-guess the amount of quark activity. We limit the total
  1289. * number of quarks, but this is much easier to "expand" as needed.
  1290. *
  1291. * Any two items with the same inscription will have the same "quark"
  1292. * index, which should greatly reduce the need for inscription space.
  1293. *
  1294. * Note that "quark zero" is NULL and should not be "dereferenced".
  1295. */
  1296. /*
  1297. * Add a new "quark" to the set of quarks.
  1298. */
  1299. s16b quark_add(cptr str)
  1300. {
  1301. int i;
  1302. /* Look for an existing quark */
  1303. for (i = 1; i < quark__num; i++)
  1304. {
  1305. /* Check for equality */
  1306. if (streq(quark__str[i], str)) return (i);
  1307. }
  1308. /* Paranoia -- Require room */
  1309. if (quark__num == QUARK_MAX) return (0);
  1310. /* New maximal quark */
  1311. quark__num = i + 1;
  1312. /* Add a new quark */
  1313. quark__str[i] = string_make(str);
  1314. /* Return the index */
  1315. return (i);
  1316. }
  1317. /*
  1318. * This function looks up a quark
  1319. */
  1320. cptr quark_str(s16b i)
  1321. {
  1322. cptr q;
  1323. /* Verify */
  1324. if ((i < 0) || (i >= quark__num)) i = 0;
  1325. /* Access the quark */
  1326. q = quark__str[i];
  1327. /* Return the quark */
  1328. return (q);
  1329. }
  1330. /*
  1331. * Check to make sure they haven't inscribed an item against what
  1332. * they are trying to do -Crimson
  1333. * look for "!*Erm" type, and "!* !A !f" type.
  1334. */
  1335. bool check_guard_inscription( s16b quark, char what ) {
  1336. const char *ax;
  1337. ax = quark_str(quark);
  1338. if (ax == NULL) { return FALSE; };
  1339. while ((ax=strchr(ax, '!')) != NULL) {
  1340. while (ax++ != NULL) {
  1341. if (*ax == 0) {
  1342. return FALSE; /* end of quark, stop */
  1343. }
  1344. if (*ax == ' ' || *ax == '@' || *ax == '#') {
  1345. break; /* end of segment, stop */
  1346. }
  1347. if (*ax == what) {
  1348. return TRUE; /* exact match, stop */
  1349. }
  1350. if (*ax == '*') {
  1351. /* why so much hassle? * = all, that's it */
  1352. /* return TRUE; -- well, !'B'ash if it's on the ground sucks ;) */
  1353. switch (what) { /* check for paranoid tags */
  1354. case 'd': /* no drop */
  1355. case 'h': /* no house ( sell a a key ) */
  1356. case 'k': /* no destroy */
  1357. case 's': /* no sell */
  1358. case 'v': /* no thowing */
  1359. case '=': /* force pickup */
  1360. #if 0
  1361. case 'w': /* no wear/wield */
  1362. case 't': /* no take off */
  1363. #endif
  1364. return TRUE;
  1365. };
  1366. };
  1367. /* Refilling is blocked if item must not be destroyed */
  1368. if (what == 'F' && *ax == 'k') return TRUE;
  1369. };
  1370. };
  1371. return FALSE;
  1372. }
  1373. /*
  1374. * Output a message to the top line of the screen.
  1375. *
  1376. * Break long messages into multiple pieces (40-72 chars).
  1377. *
  1378. * Allow multiple short messages to "share" the top line.
  1379. *
  1380. * Prompt the user to make sure he has a chance to read them.
  1381. *
  1382. * These messages are memorized for later reference (see above).
  1383. *
  1384. * We could do "Term_fresh()" to provide "flicker" if needed.
  1385. *
  1386. * XXX XXX XXX Note that we must be very careful about using the
  1387. * "msg_print()" functions without explicitly calling the special
  1388. * "msg_print(NULL)" function, since this may result in the loss
  1389. * of information if the screen is cleared, or if anything is
  1390. * displayed on the top line.
  1391. *
  1392. * XXX XXX XXX Note that "msg_print(NULL)" will clear the top line
  1393. * even if no messages are pending. This is probably a hack.
  1394. */
  1395. bool suppress_message = FALSE, censor_message = FALSE, suppress_boni = FALSE;
  1396. int censor_length = 0, censor_punish = 0;
  1397. void msg_print(int Ind, cptr msg_raw)
  1398. {
  1399. char msg_dup[MSG_LEN], *msg = msg_dup;
  1400. int line_len = 80; /* maximum length of a text line to be displayed;
  1401. this is client-dependant, compare c_msg_print (c-util.c) */
  1402. char msg_buf[line_len + 2 + 2 * 80]; /* buffer for 1 line. + 2 bytes for colour code (+2*80 bytes for colour codeeeezz) */
  1403. char msg_minibuf[3]; /* temp buffer for adding characters */
  1404. int text_len, msg_scan = 0, space_scan, tab_spacer = 0, tmp;
  1405. char colour_code = 'w';
  1406. bool no_colour_code = FALSE;
  1407. bool first_character = TRUE;
  1408. // bool is_chat = ((msg_raw != NULL) && (strlen(msg_raw) > 2) && (msg_raw[2] == '['));
  1409. bool client_ctrlo = FALSE, client_chat = FALSE, client_all = FALSE;
  1410. /* for {- feature */
  1411. char prev_colour_code = 'w', first_colour_code = 'w';
  1412. bool first_colour_code_set = FALSE;
  1413. /* backward msg window width hack for windows clients (non-x11 clients rather) */
  1414. if (!is_newer_than(&Players[Ind]->version, 4, 4, 5, 3, 0, 0) && !strcmp(Players[Ind]->realname, "PLAYER")) line_len = 72;
  1415. /* Pfft, sorry to bother you.... --JIR-- */
  1416. if (suppress_message) return;
  1417. /* no message? */
  1418. if (msg_raw == NULL) return;
  1419. strcpy(msg_dup, msg_raw); /* in case msg_raw was constant */
  1420. /* censor swear words? */
  1421. if (censor_message) {
  1422. /* skip the name of the sender, etc. */
  1423. censor_punish = handle_censor(msg + strlen(msg) - censor_length);
  1424. /* we just needed to get censor_punish at least once, above.
  1425. Now don't really censor the string if the player doesn't want to.. */
  1426. if (!Players[Ind]->censor_swearing) strcpy(msg_dup, msg_raw);
  1427. }
  1428. /* marker for client: add message to 'chat-only buffer', not to 'nochat buffer' */
  1429. if (msg[0] == '\375') {
  1430. client_chat = TRUE;
  1431. msg++;
  1432. /* hack: imply that chat-only messages are also always important messages */
  1433. client_ctrlo = TRUE;
  1434. }
  1435. /* marker for client: add message to 'nochat buffer' AND to 'chat-only buffer' */
  1436. else if (msg[0] == '\374') {
  1437. client_all = TRUE;
  1438. msg++;
  1439. /* hack: imply that messages that go to chat-buffer are also always important messages */
  1440. client_ctrlo = TRUE;
  1441. }
  1442. /* ADDITIONAL marker for client: add message to CTRL+O 'important scrollback buffer' */
  1443. if (msg[0] == '\376') {
  1444. client_ctrlo = TRUE;
  1445. msg++;
  1446. }
  1447. /* note: neither \375 nor \374 means:
  1448. add message to 'nochat buffer', but not to 'chat-only buffer' (default) */
  1449. /* neutralize markers if client version too old */
  1450. if (!is_newer_than(&Players[Ind]->version, 4, 4, 2, 0, 0, 0))
  1451. client_ctrlo = client_chat = client_all = FALSE;
  1452. #if 1 /* String longer than 1 line? -> Split it up! --C. Blue-- */
  1453. while (msg != NULL && msg[msg_scan] != '\0') {
  1454. /* Start a new line */
  1455. strcpy(msg_buf, "");
  1456. text_len = 0;
  1457. /* Tabbing the line? */
  1458. msg_minibuf[0] = ' ';
  1459. msg_minibuf[1] = '\0';
  1460. #if 0 /* 0'ed to remove backward compatibility via '~' character. We want to switch to \374..6 codes exlusively */
  1461. if (is_chat && tab_spacer) {
  1462. /* Start the padding for chat messages with '~' */
  1463. strcat(msg_buf, "~");
  1464. tmp = tab_spacer - 1;
  1465. } else {
  1466. tmp = tab_spacer;
  1467. }
  1468. #else
  1469. tmp = tab_spacer;
  1470. #endif
  1471. while (tmp--) {
  1472. text_len++;
  1473. strcat(msg_buf, msg_minibuf);
  1474. }
  1475. /* Prefixing colour code? */
  1476. if (colour_code) {
  1477. msg_minibuf[0] = '\377';
  1478. msg_minibuf[1] = colour_code;
  1479. msg_minibuf[2] = '\0';
  1480. strcat(msg_buf, msg_minibuf);
  1481. /// colour_code = 0;
  1482. }
  1483. /* Process the string... */
  1484. while (text_len < line_len) {
  1485. switch (msg[msg_scan]) {
  1486. case '\0': /* String ends! */
  1487. text_len = line_len;
  1488. continue;
  1489. case '\377': /* Colour code! Text length does not increase. */
  1490. if (!no_colour_code) {
  1491. /* broken \377 at the end of the text? ignore */
  1492. if (color_char_to_attr(msg[msg_scan + 1]) == -1) {
  1493. msg_scan++;
  1494. continue;
  1495. }
  1496. /* Capture double \377 which stand for a normal { char instead of a colour code: */
  1497. if (msg[msg_scan + 1] != '\377') {
  1498. msg_minibuf[0] = msg[msg_scan];
  1499. msg_scan++;
  1500. /* needed for new '\377-' feature in multi-line messages: resolve it to actual colour */
  1501. if (msg[msg_scan] == '-') {
  1502. msg[msg_scan] = colour_code = first_colour_code; //prev_colour_code
  1503. } else {
  1504. prev_colour_code = colour_code = msg[msg_scan];
  1505. if (!first_colour_code_set) {
  1506. first_colour_code_set = TRUE;
  1507. first_colour_code = colour_code;
  1508. }
  1509. }
  1510. msg_minibuf[1] = colour_code;
  1511. msg_scan++;
  1512. msg_minibuf[2] = '\0';
  1513. strcat(msg_buf, msg_minibuf);
  1514. break;
  1515. }
  1516. no_colour_code = TRUE;
  1517. } else no_colour_code = FALSE;
  1518. /* fall through if it's a '{' character */
  1519. default: /* Text length increases by another character.. */
  1520. /* Depending on message type, remember to tab the following
  1521. lines accordingly to make it look better ^^
  1522. depending on the first character of this line. */
  1523. if (first_character) {
  1524. switch (msg[msg_scan]) {
  1525. case '*': tab_spacer = 2; break; /* Kill message */
  1526. case '[': /* Chat message */
  1527. #if 0
  1528. tab_spacer = 1;
  1529. #else
  1530. {
  1531. const char *bracket = strchr(&msg[msg_scan], ']');
  1532. if (bracket) {
  1533. const char *ptr = &msg[msg_scan];
  1534. /* Pad lines according to how long the name is - mikaelh */
  1535. tab_spacer = bracket - &msg[msg_scan] + 2;
  1536. /* Ignore space reserved for colour codes:
  1537. Guild chat has coloured [ ] brackets. - C. Blue */
  1538. while ((ptr = strchr(ptr, '\377')) && ptr < bracket) {
  1539. ptr++;
  1540. tab_spacer -= 2; /* colour code consists of two chars
  1541. (we can guarantee that here, since the server
  1542. generated this colour code) */
  1543. }
  1544. /* Hack: multiline /me emotes */
  1545. if (tab_spacer > 70) tab_spacer = 1;
  1546. /* Paranoia */
  1547. if (tab_spacer < 1) tab_spacer = 1;
  1548. if (tab_spacer > 30) tab_spacer = 30;
  1549. } else {
  1550. /* No ']' */
  1551. tab_spacer = 1;
  1552. }
  1553. }
  1554. #endif
  1555. break;
  1556. default: tab_spacer = 1;
  1557. }
  1558. }
  1559. /* remember first actual chat colour (guild chat changes
  1560. colour a few times for [..] brackets and name).
  1561. This is for {- etc feature.
  1562. However, if there is no new colour specified before
  1563. beginning of chat text then use the one we had, or {-
  1564. wouldn't work correctly in private chat anymore. - C. Blue */
  1565. if (msg[msg_scan] == ']' &&
  1566. #if 0 /* this is wrong, because the colour code COULD already be from \\a feature! */
  1567. ((msg[msg_scan + 1] == ' ' && msg[msg_scan + 2] == '\377') ||
  1568. #endif
  1569. msg[msg_scan + 1] == '\377') {
  1570. first_colour_code_set = FALSE;
  1571. }
  1572. /* Process text.. */
  1573. first_character = FALSE;
  1574. msg_minibuf[0] = msg[msg_scan];
  1575. msg_minibuf[1] = '\0';
  1576. strcat(msg_buf, msg_minibuf);
  1577. msg_scan++;
  1578. text_len++;
  1579. /* Avoid cutting words in two */
  1580. if ((text_len == line_len) && (msg[msg_scan] != '\0')
  1581. && (
  1582. (msg[msg_scan - 1] >= 'A' && msg[msg_scan - 1] <= 'Z') ||
  1583. (msg[msg_scan - 1] >= 'a' && msg[msg_scan - 1] <= 'z') ||
  1584. (msg[msg_scan - 1] >= '0' && msg[msg_scan - 1] <= '9') ||
  1585. msg[msg_scan - 1] == '(' ||
  1586. msg[msg_scan - 1] == '[' ||
  1587. msg[msg_scan - 1] == '{' ||
  1588. #if 0
  1589. msg[msg_scan - 1] == ')' ||
  1590. msg[msg_scan - 1] == ']' ||
  1591. msg[msg_scan - 1] == '}' ||
  1592. #endif
  1593. /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
  1594. msg[msg_scan - 1] == '+' || msg[msg_scan - 1] == '-' ||
  1595. /* Don't break colour codes */
  1596. msg[msg_scan - 1] == '\377'
  1597. ) && (
  1598. (msg[msg_scan] >= 'A' && msg[msg_scan] <= 'Z') ||
  1599. (msg[msg_scan] >= 'a' && msg[msg_scan] <= 'z') ||
  1600. (msg[msg_scan] >= '0' && msg[msg_scan] <= '9') ||
  1601. #if 0
  1602. msg[msg_scan] == '(' ||
  1603. msg[msg_scan] == '[' ||
  1604. msg[msg_scan] == '{' ||
  1605. #endif
  1606. msg[msg_scan] == ')' ||
  1607. msg[msg_scan] == ']' ||
  1608. msg[msg_scan] == '}' ||
  1609. /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
  1610. msg[msg_scan] == '+' || msg[msg_scan] == '-' ||
  1611. /* interpunction at the end of a sentence */
  1612. msg[msg_scan] == '.' || msg[msg_scan] == ',' ||
  1613. msg[msg_scan] == ';' || msg[msg_scan] == ':' ||
  1614. msg[msg_scan] == '!' || msg[msg_scan] == '?' ||
  1615. /* Don't break colour codes */
  1616. msg[msg_scan] == '\377'
  1617. )) {
  1618. space_scan = msg_scan;
  1619. do {
  1620. space_scan--;
  1621. } while (((msg[space_scan - 1] >= 'A' && msg[space_scan - 1] <= 'Z') ||
  1622. (msg[space_scan - 1] >= 'a' && msg[space_scan - 1] <= 'z') ||
  1623. (msg[space_scan - 1] >= '0' && msg[space_scan - 1] <= '9') ||
  1624. #if 0
  1625. msg[space_scan - 1] == ')' ||
  1626. msg[space_scan - 1] == ']' ||
  1627. msg[space_scan - 1] == '}' ||
  1628. #endif
  1629. msg[space_scan - 1] == '(' ||
  1630. msg[space_scan - 1] == '[' ||
  1631. msg[space_scan - 1] == '{' ||
  1632. /* (maybe too much) for pasting items to chat, (+1) or (-2,0) : */
  1633. msg[space_scan - 1] == '+' || msg[space_scan - 1] == '-' ||
  1634. /* pasting flags to chat ("SLAY_EVIL") */
  1635. msg[space_scan - 1] == '_' ||
  1636. msg[space_scan - 1] == '\377'
  1637. ) && space_scan > 0);
  1638. /* Simply cut words that are very long - mikaelh */
  1639. if (msg_scan - space_scan > 36) {
  1640. space_scan = msg_scan;
  1641. }
  1642. if (space_scan) {
  1643. msg_buf[strlen(msg_buf) - msg_scan + space_scan] = '\0';
  1644. msg_scan = space_scan;
  1645. }
  1646. }
  1647. }
  1648. }
  1649. Send_message(Ind, format("%s%s%s",
  1650. client_chat ? "\375" : (client_all ? "\374" : ""),
  1651. client_ctrlo ? "\376" : "",
  1652. msg_buf));
  1653. /* hack: avoid trailing space in the next sub-line */
  1654. if (msg[msg_scan] == ' ') msg_scan++;
  1655. }
  1656. if (msg == NULL) Send_message(Ind, msg);
  1657. return;
  1658. #endif // enable line breaks?
  1659. Send_message(Ind, format("%s%s%s",
  1660. client_chat ? "\375" : (client_all ? "\374" : ""),
  1661. client_ctrlo ? "\376" : "",
  1662. msg));
  1663. }
  1664. void msg_broadcast(int Ind, cptr msg)
  1665. {
  1666. int i;
  1667. /* Tell every player */
  1668. for (i = 1; i <= NumPlayers; i++)
  1669. {
  1670. /* Skip disconnected players */
  1671. if (Players[i]->conn == NOT_CONNECTED)
  1672. continue;
  1673. /* Skip the specified player */
  1674. if (i == Ind)
  1675. continue;
  1676. /* Tell this one */
  1677. msg_print(i, msg);
  1678. }
  1679. }
  1680. void msg_admins(int Ind, cptr msg)
  1681. {
  1682. int i;
  1683. /* Tell every player */
  1684. for (i = 1; i <= NumPlayers; i++)
  1685. {
  1686. /* Skip disconnected players */
  1687. if (Players[i]->conn == NOT_CONNECTED)
  1688. continue;
  1689. /* Skip the specified player */
  1690. if (i == Ind)
  1691. continue;
  1692. /* Skip non-admins */
  1693. if (!is_admin(Players[i]))
  1694. continue;
  1695. /* Tell this one */
  1696. msg_print(i, msg);
  1697. }
  1698. }
  1699. void msg_broadcast_format(int Ind, cptr fmt, ...)
  1700. {
  1701. // int i;
  1702. va_list vp;
  1703. char buf[1024];
  1704. /* Begin the Varargs Stuff */
  1705. va_start(vp, fmt);
  1706. /* Format the args, save the length */
  1707. (void)vstrnfmt(buf, 1024, fmt, vp);
  1708. /* End the Varargs Stuff */
  1709. va_end(vp);
  1710. msg_broadcast(Ind, buf);
  1711. }
  1712. /* Send a formatted message only to admin chars. -Jir- */
  1713. void msg_admin(cptr fmt, ...)
  1714. //void msg_admin(int Ind, cptr fmt, ...)
  1715. {
  1716. int i;
  1717. player_type *p_ptr;
  1718. va_list vp;
  1719. char buf[1024];
  1720. /* Begin the Varargs Stuff */
  1721. va_start(vp, fmt);
  1722. /* Format the args, save the length */
  1723. (void)vstrnfmt(buf, 1024, fmt, vp);
  1724. /* End the Varargs Stuff */
  1725. va_end(vp);
  1726. /* Tell every admin */
  1727. for (i = 1; i <= NumPlayers; i++)
  1728. {
  1729. p_ptr = Players[i];
  1730. /* Skip disconnected players */
  1731. if (p_ptr->conn == NOT_CONNECTED)
  1732. continue;
  1733. /* Tell Mama */
  1734. if (is_admin(p_ptr))
  1735. msg_print(i, buf);
  1736. }
  1737. }
  1738. /*
  1739. * Display a formatted message, using "vstrnfmt()" and "msg_print()".
  1740. */
  1741. void msg_format(int Ind, cptr fmt, ...)
  1742. {
  1743. va_list vp;
  1744. char buf[1024];
  1745. /* Begin the Varargs Stuff */
  1746. va_start(vp, fmt);
  1747. /* Format the args, save the length */
  1748. (void)vstrnfmt(buf, 1024, fmt, vp);
  1749. /* End the Varargs Stuff */
  1750. va_end(vp);
  1751. /* Display */
  1752. msg_print(Ind, buf);
  1753. }
  1754. /*
  1755. * Send a message to ever…

Large files files are truncated, but you can click here to view the full file