PageRenderTime 102ms CodeModel.GetById 23ms RepoModel.GetById 0ms 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
  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 everyone on a floor.
  1756. */
  1757. static void floor_msg(struct worldpos *wpos, cptr msg) {
  1758. int i;
  1759. //system-msg, currently unused anyway- if(cfg.log_u) s_printf("[%s] %s\n", Players[sender]->name, msg);
  1760. /* Check for this guy */
  1761. for (i = 1; i <= NumPlayers; i++) {
  1762. if (Players[i]->conn == NOT_CONNECTED) continue;
  1763. /* Check this guy */
  1764. if (inarea(wpos, &Players[i]->wpos)) msg_print(i, msg);
  1765. }
  1766. }
  1767. /*
  1768. * Send a formatted message to everyone on a floor. (currently unused)
  1769. */
  1770. void floor_msg_format(struct worldpos *wpos, cptr fmt, ...) {
  1771. va_list vp;
  1772. char buf[1024];
  1773. /* Begin the Varargs Stuff */
  1774. va_start(vp, fmt);
  1775. /* Format the args, save the length */
  1776. (void)vstrnfmt(buf, 1024, fmt, vp);
  1777. /* End the Varargs Stuff */
  1778. va_end(vp);
  1779. /* Display */
  1780. floor_msg(wpos, buf);
  1781. }
  1782. /*
  1783. * Send a message to everyone on a floor, considering ignorance.
  1784. */
  1785. static void floor_msg_ignoring(int sender, struct worldpos *wpos, cptr msg) {
  1786. int i;
  1787. if(cfg.log_u) s_printf("(%d,%d,%d)%s\n", wpos->wx, wpos->wy, wpos->wz, msg + 2);// Players[sender]->name, msg);
  1788. /* Check for this guy */
  1789. for (i = 1; i <= NumPlayers; i++) {
  1790. if (Players[i]->conn == NOT_CONNECTED) continue;
  1791. if (check_ignore(i, sender)) continue;
  1792. /* Check this guy */
  1793. if (inarea(wpos, &Players[i]->wpos)) msg_print(i, msg);
  1794. }
  1795. }
  1796. /*
  1797. * Send a formatted message to everyone on a floor, considering ignorance.
  1798. */
  1799. static void floor_msg_format_ignoring(int sender, struct worldpos *wpos, cptr fmt, ...) {
  1800. va_list vp;
  1801. char buf[1024];
  1802. /* Begin the Varargs Stuff */
  1803. va_start(vp, fmt);
  1804. /* Format the args, save the length */
  1805. (void)vstrnfmt(buf, 1024, fmt, vp);
  1806. /* End the Varargs Stuff */
  1807. va_end(vp);
  1808. /* Display */
  1809. floor_msg_ignoring(sender, wpos, buf);
  1810. }
  1811. /*
  1812. * Send a message to everyone on the world surface. (for season change)
  1813. */
  1814. void world_surface_msg(cptr msg) {
  1815. int i;
  1816. //system-msg, currently unused anyway- if(cfg.log_u) s_printf("[%s] %s\n", Players[sender]->name, msg);
  1817. /* Check for this guy */
  1818. for (i = 1; i <= NumPlayers; i++) {
  1819. if (Players[i]->conn == NOT_CONNECTED) continue;
  1820. /* Check this guy */
  1821. if (Players[i]->wpos.wz == 0) msg_print(i, msg);
  1822. }
  1823. }
  1824. /*
  1825. * Display a message to everyone who is in sight on another player.
  1826. *
  1827. * This is mainly used to keep other players advised of actions done
  1828. * by a player. The message is not sent to the player who performed
  1829. * the action.
  1830. */
  1831. void msg_print_near(int Ind, cptr msg)
  1832. {
  1833. player_type *p_ptr = Players[Ind];
  1834. int y, x, i;
  1835. struct worldpos *wpos;
  1836. wpos=&p_ptr->wpos;
  1837. if(p_ptr->admin_dm) return;
  1838. y = p_ptr->py;
  1839. x = p_ptr->px;
  1840. /* Check each player */
  1841. for (i = 1; i <= NumPlayers; i++)
  1842. {
  1843. /* Check this player */
  1844. p_ptr = Players[i];
  1845. /* Make sure this player is in the game */
  1846. if (p_ptr->conn == NOT_CONNECTED) continue;
  1847. /* Don't send the message to the player who caused it */
  1848. if (Ind == i) continue;
  1849. /* Make sure this player is at this depth */
  1850. if (!inarea(&p_ptr->wpos, wpos)) continue;
  1851. /* Can he see this player? */
  1852. if (p_ptr->cave_flag[y][x] & CAVE_VIEW)
  1853. {
  1854. /* Send the message */
  1855. msg_print(i, msg);
  1856. }
  1857. }
  1858. }
  1859. /* Whispering: Send message to adjacent players */
  1860. void msg_print_verynear(int Ind, cptr msg)
  1861. {
  1862. player_type *p_ptr = Players[Ind];
  1863. int y, x, i;
  1864. struct worldpos *wpos;
  1865. wpos=&p_ptr->wpos;
  1866. // if(p_ptr->admin_dm) return;
  1867. y = p_ptr->py;
  1868. x = p_ptr->px;
  1869. /* Check each player */
  1870. for (i = 1; i <= NumPlayers; i++)
  1871. {
  1872. /* Check this player */
  1873. p_ptr = Players[i];
  1874. /* Make sure this player is in the game */
  1875. if (p_ptr->conn == NOT_CONNECTED) continue;
  1876. /* Don't send the message to the player who caused it */
  1877. if (Ind == i) continue;
  1878. /* Make sure this player is at this depth */
  1879. if (!inarea(&p_ptr->wpos, wpos)) continue;
  1880. /* Is he in range? */
  1881. if (abs(p_ptr->py - y) <= 1 && abs(p_ptr->px - x) <= 1) {
  1882. /* Send the message */
  1883. msg_print(i, msg);
  1884. }
  1885. }
  1886. }
  1887. /*
  1888. * Same as above, except send a formatted message.
  1889. */
  1890. void msg_format_near(int Ind, cptr fmt, ...)
  1891. {
  1892. va_list vp;
  1893. char buf[1024];
  1894. /* Begin the Varargs Stuff */
  1895. va_start(vp, fmt);
  1896. /* Format the args, save the length */
  1897. (void)vstrnfmt(buf, 1024, fmt, vp);
  1898. /* End the Varargs Stuff */
  1899. va_end(vp);
  1900. /* Display */
  1901. msg_print_near(Ind, buf);
  1902. }
  1903. /* for whispering */
  1904. void msg_format_verynear(int Ind, cptr fmt, ...)
  1905. {
  1906. va_list vp;
  1907. char buf[1024];
  1908. /* Begin the Varargs Stuff */
  1909. va_start(vp, fmt);
  1910. /* Format the args, save the length */
  1911. (void)vstrnfmt(buf, 1024, fmt, vp);
  1912. /* End the Varargs Stuff */
  1913. va_end(vp);
  1914. /* Display */
  1915. msg_print_verynear(Ind, buf);
  1916. }
  1917. /* location-based - also, skip player Ind if non-zero */
  1918. void msg_print_near_site(int y, int x, worldpos *wpos, int Ind, bool view, cptr msg)
  1919. {
  1920. int i, d;
  1921. player_type *p_ptr;
  1922. /* Check each player */
  1923. for (i = 1; i <= NumPlayers; i++) {
  1924. /* Check this player */
  1925. p_ptr = Players[i];
  1926. /* Make sure this player is in the game */
  1927. if (p_ptr->conn == NOT_CONNECTED) continue;
  1928. /* Skip specified player, if any */
  1929. if (i == Ind) continue;
  1930. /* Make sure this player is at this depth */
  1931. if (!inarea(&p_ptr->wpos, wpos)) continue;
  1932. /* Can (s)he see the site? */
  1933. if (view) {
  1934. if (!(p_ptr->cave_flag[y][x] & CAVE_VIEW)) continue;
  1935. } else { /* can (s)he hear it? */
  1936. /* within audible range? */
  1937. d = distance(y, x, Players[i]->py, Players[i]->px);
  1938. /* NOTE: should be consistent with sound_near_site() */
  1939. if (d > MAX_SIGHT) continue;
  1940. }
  1941. /* Send the message */
  1942. msg_print(i, msg);
  1943. }
  1944. }
  1945. /*
  1946. * Same as above, except send a formatted message.
  1947. */
  1948. void msg_format_near_site(int y, int x, worldpos *wpos, int Ind, bool view, cptr fmt, ...)
  1949. {
  1950. va_list vp;
  1951. char buf[1024];
  1952. /* Begin the Varargs Stuff */
  1953. va_start(vp, fmt);
  1954. /* Format the args, save the length */
  1955. (void)vstrnfmt(buf, 1024, fmt, vp);
  1956. /* End the Varargs Stuff */
  1957. va_end(vp);
  1958. /* Display */
  1959. msg_print_near_site(y, x, wpos, Ind, view, buf);
  1960. }
  1961. /*
  1962. * Send a message about a monster to everyone who can see it.
  1963. * Monster name is appended at the beginning. (XXX kludgie!) - Jir -
  1964. *
  1965. * Example: msg_print_near_monster(m_idx, "wakes up.");
  1966. */
  1967. /*
  1968. * TODO: allow format
  1969. * TODO: distinguish 'witnessing' and 'hearing'
  1970. */
  1971. void msg_print_near_monster(int m_idx, cptr msg)
  1972. {
  1973. int i;
  1974. player_type *p_ptr;
  1975. cave_type **zcave;
  1976. char m_name[MNAME_LEN];
  1977. monster_type *m_ptr = &m_list[m_idx];
  1978. worldpos *wpos=&m_ptr->wpos;
  1979. if(!(zcave=getcave(wpos))) return;
  1980. /* Check each player */
  1981. for (i = 1; i <= NumPlayers; i++)
  1982. {
  1983. /* Check this player */
  1984. p_ptr = Players[i];
  1985. /* Make sure this player is in the game */
  1986. if (p_ptr->conn == NOT_CONNECTED) continue;
  1987. /* Make sure this player is at this depth */
  1988. if (!inarea(&p_ptr->wpos, wpos)) continue;
  1989. /* Skip if not visible */
  1990. if (!p_ptr->mon_vis[m_idx]) continue;
  1991. /* Can he see this player? */
  1992. // if (!p_ptr->cave_flag[y][x] & CAVE_VIEW) continue;
  1993. /* Acquire the monster name */
  1994. monster_desc(i, m_name, m_idx, 0);
  1995. msg_format(i, "%^s %s", m_name, msg);
  1996. }
  1997. }
  1998. /* send a message to all online party members */
  1999. void msg_party_format(int Ind, cptr fmt, ...) {
  2000. int i;
  2001. char buf[1024];
  2002. va_list vp;
  2003. /* Begin the Varargs Stuff */
  2004. va_start(vp, fmt);
  2005. /* Format the args, save the length */
  2006. (void)vstrnfmt(buf, 1024, fmt, vp);
  2007. /* End the Varargs Stuff */
  2008. va_end(vp);
  2009. /* Tell every player */
  2010. for (i = 1; i <= NumPlayers; i++) {
  2011. /* Skip disconnected players */
  2012. if (Players[i]->conn == NOT_CONNECTED)
  2013. continue;
  2014. #if 0
  2015. /* Skip the specified player */
  2016. if (i == Ind)
  2017. continue;
  2018. #endif
  2019. /* skip players not in his party */
  2020. if (Players[i]->party != Players[Ind]->party)
  2021. continue;
  2022. /* Tell this one */
  2023. msg_print(i, buf);
  2024. }
  2025. }
  2026. /* send a message to all online guild members */
  2027. void msg_guild_format(int Ind, cptr fmt, ...) {
  2028. int i;
  2029. char buf[1024];
  2030. va_list vp;
  2031. /* Begin the Varargs Stuff */
  2032. va_start(vp, fmt);
  2033. /* Format the args, save the length */
  2034. (void)vstrnfmt(buf, 1024, fmt, vp);
  2035. /* End the Varargs Stuff */
  2036. va_end(vp);
  2037. /* Tell every player */
  2038. for (i = 1; i <= NumPlayers; i++) {
  2039. /* Skip disconnected players */
  2040. if (Players[i]->conn == NOT_CONNECTED)
  2041. continue;
  2042. #if 0
  2043. /* Skip the specified player */
  2044. if (i == Ind)
  2045. continue;
  2046. #endif
  2047. /* skip players not in his guild */
  2048. if (Players[i]->guild != Players[Ind]->guild)
  2049. continue;
  2050. /* Tell this one */
  2051. msg_print(i, buf);
  2052. }
  2053. }
  2054. #if 0 /* unused atm */
  2055. static char* dodge_diz(int chance) {
  2056. if (chance < 5)
  2057. return "almost no";
  2058. else if (chance < 14)
  2059. return "a slight";
  2060. else if (chance < 23)
  2061. return "a significant";
  2062. else if (chance < 30)
  2063. return "a good";
  2064. else if (chance < 40)
  2065. return "a very good";
  2066. else
  2067. return "a high";
  2068. }
  2069. #endif
  2070. /*
  2071. * Dodge Chance Feedback.
  2072. */
  2073. void use_ability_blade(int Ind)
  2074. {
  2075. player_type *p_ptr = Players[Ind];
  2076. #ifndef NEW_DODGING
  2077. int dun_level = getlevel(&p_ptr->wpos);
  2078. int chance = p_ptr->dodge_level - (dun_level * 5 / 6);
  2079. if (chance < 0) chance = 0;
  2080. if (chance > DODGE_MAX_CHANCE) chance = DODGE_MAX_CHANCE; // see DODGE_MAX_CHANCE in melee1.c
  2081. // if (is_admin(p_ptr))
  2082. msg_format(Ind, "You have a %d%% chance of dodging a level %d monster.", chance, dun_level);
  2083. #if 0
  2084. if (chance < 5)
  2085. msg_format(Ind, "You have almost no chance of dodging a level %d monster.", dun_level);
  2086. else if (chance < 10)
  2087. msg_format(Ind, "You have a slight chance of dodging a level %d monster.", dun_level);
  2088. else if (chance < 20)
  2089. msg_format(Ind, "You have a significant chance of dodging a level %d monster.", dun_level);
  2090. else if (chance < 40)
  2091. msg_format(Ind, "You have a large chance of dodging a level %d monster.", dun_level);
  2092. else if (chance < 70)
  2093. msg_format(Ind, "You have a high chance of dodging a level %d monster.", dun_level);
  2094. else
  2095. msg_format(Ind, "You will usually dodge a level %d monster.", dun_level);
  2096. #endif
  2097. #else
  2098. int lev;
  2099. lev = p_ptr->lev * 2 < 127 ? p_ptr->lev * 2 : 127;
  2100. if (is_admin(p_ptr))
  2101. msg_format(Ind, "You have a %d%%/%d%% chance of dodging a level %d/%d monster.",
  2102. apply_dodge_chance(Ind, p_ptr->lev), apply_dodge_chance(Ind, lev), p_ptr->lev, lev);
  2103. /*
  2104. msg_format(Ind, "You have %s/%s chance of dodging a level %d/%d monster.",
  2105. dodge_diz(apply_dodge_chance(Ind, p_ptr->lev)), dodge_diz(apply_dodge_chance(Ind, lev)),
  2106. p_ptr->lev, lev);
  2107. msg_format(Ind, "You have %s chance of dodging a level %d monster.",
  2108. dodge_diz(apply_dodge_chance(Ind, p_ptr->lev)), p_ptr->lev);
  2109. */
  2110. else msg_format(Ind, "You have a %d%% chance of dodging a level %d monster's attack.",
  2111. apply_dodge_chance(Ind, p_ptr->lev), p_ptr->lev);
  2112. #endif
  2113. return;
  2114. }
  2115. void check_parryblock(int Ind)
  2116. {
  2117. #ifdef ENABLE_NEW_MELEE
  2118. char msg[80];
  2119. player_type *p_ptr = Players[Ind];
  2120. if (is_admin(p_ptr)) {
  2121. msg_format(Ind, "You have exactly %d%%/%d%% base chance of parrying/blocking.",
  2122. p_ptr->weapon_parry, p_ptr->shield_deflect);
  2123. msg_format(Ind, "You have exactly %d%%/%d%% real chance of parrying/blocking.",
  2124. apply_parry_chance(p_ptr, p_ptr->weapon_parry), apply_block_chance(p_ptr, p_ptr->shield_deflect));
  2125. } else {
  2126. if (!apply_parry_chance(p_ptr, p_ptr->weapon_parry))
  2127. strcpy(msg, "You cannot parry at the moment. ");
  2128. //msg_print(Ind, "You cannot parry at the moment.");
  2129. #if 0
  2130. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 5)
  2131. msg_print(Ind, "You have almost no chance of parrying.");
  2132. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 10)
  2133. msg_print(Ind, "You have a slight chance of parrying.");
  2134. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 20)
  2135. msg_print(Ind, "You have a significant chance of parrying.");
  2136. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 30)
  2137. msg_print(Ind, "You have a good chance of parrying.");
  2138. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 40)
  2139. msg_print(Ind, "You have a very good chance of parrying.");
  2140. else if (apply_parry_chance(p_ptr, p_ptr->weapon_parry) < 50)
  2141. msg_print(Ind, "You have an excellent chance of parrying.");
  2142. else
  2143. msg_print(Ind, "You have a superb chance of parrying.");
  2144. #else
  2145. else strcpy(msg, format("You have a %d%% chance of parrying. ",
  2146. apply_parry_chance(p_ptr, p_ptr->weapon_parry)));
  2147. #endif
  2148. if (!apply_block_chance(p_ptr, p_ptr->shield_deflect))
  2149. strcat(msg, "You cannot block at the moment.");
  2150. //msg_print(Ind, "You cannot block at the moment.");
  2151. #if 0
  2152. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 5)
  2153. msg_print(Ind, "You have almost no chance of blocking.");
  2154. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 14)
  2155. msg_print(Ind, "You have a slight chance of blocking.");
  2156. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 23)
  2157. msg_print(Ind, "You have a significant chance of blocking.");
  2158. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 33)
  2159. msg_print(Ind, "You have a good chance of blocking.");
  2160. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 44)
  2161. msg_print(Ind, "You have a very good chance of blocking.");
  2162. else if (apply_block_chance(p_ptr, p_ptr->shield_deflect) < 55)
  2163. msg_print(Ind, "You have an excellent chance of blocking.");
  2164. else
  2165. msg_print(Ind, "You have a superb chance of blocking.");
  2166. #else
  2167. else strcat(msg, format("You have a %d%% chance of blocking.",
  2168. apply_block_chance(p_ptr, p_ptr->shield_deflect)));
  2169. #endif
  2170. msg_print(Ind, msg);
  2171. }
  2172. #endif
  2173. return;
  2174. }
  2175. void toggle_shoot_till_kill(int Ind)
  2176. {
  2177. player_type *p_ptr = Players[Ind];
  2178. if (p_ptr->shoot_till_kill) {
  2179. msg_print(Ind, "\377wFire-till-kill mode now off.");
  2180. p_ptr->shooting_till_kill = FALSE;
  2181. } else {
  2182. msg_print(Ind, "\377wFire-till-kill mode now on!");
  2183. }
  2184. p_ptr->shoot_till_kill = !p_ptr->shoot_till_kill;
  2185. s_printf("SHOOT_TILL_KILL: Player %s toggles %s.\n", p_ptr->name, p_ptr->shoot_till_kill ? "true" : "false");
  2186. p_ptr->redraw |= PR_STATE;
  2187. return;
  2188. }
  2189. void toggle_dual_mode(int Ind)
  2190. {
  2191. player_type *p_ptr = Players[Ind];
  2192. if (p_ptr->dual_mode)
  2193. msg_print(Ind, "\377wDual-wield mode: Main-hand. (This disables all dual-wield boni.)");
  2194. else
  2195. msg_print(Ind, "\377wDual-wield mode: Dual-hand.");
  2196. p_ptr->dual_mode = !p_ptr->dual_mode;
  2197. s_printf("DUAL_MODE: Player %s toggles %s.\n", p_ptr->name, p_ptr->dual_mode ? "true" : "false");
  2198. p_ptr->redraw |= PR_STATE | PR_PLUSSES;
  2199. calc_boni(Ind);
  2200. return;
  2201. }
  2202. #ifdef CENSOR_SWEARING
  2203. /* similar to strstr(), but catches char repetitions and swap-arounds.
  2204. TODO: current implementation is pretty naive, need to use more effective algo when less lazy. */
  2205. #define GET_MOST_DELAYED_MATCH /* must be enabled */
  2206. static char* censor_strstr(char *line, char *word, int *eff_len) {
  2207. char bufl[MSG_LEN], bufs[NAME_LEN], *best = NULL;
  2208. int i, j, add;
  2209. if (line[0] == '\0') return (char*)NULL;
  2210. if (word[0] == '\0') return (char*)NULL;//or line, I guess.
  2211. strcpy(bufl, line);
  2212. strcpy(bufs, word);
  2213. *eff_len = 0;
  2214. /* (Note: Since we're returning line[] without any char-mapping, we
  2215. can only do replacements here, not shortening/expanding. */
  2216. /* replace 'ck' or 'kc' by just 'kk' */
  2217. i = 0;
  2218. while (bufl[i] && bufl[i + 1]) {
  2219. if (bufl[i] == 'c' && bufl[i + 1] == 'k') bufl[i] = 'k';
  2220. else if (bufl[i] == 'k' && bufl[i + 1] == 'c') bufl[i + 1] = 'k';
  2221. i++;
  2222. }
  2223. i = 0;
  2224. while (bufs[i] && bufs[i + 1]) {
  2225. if (bufs[i] == 'c' && bufs[i + 1] == 'k') bufs[i] = 'k';
  2226. else if (bufs[i] == 'k' && bufs[i + 1] == 'c') bufs[i + 1] = 'k';
  2227. i++;
  2228. }
  2229. /* search while allowing repetitions/swapping of characters.
  2230. Important: Get the furthest possible match for the starting char of
  2231. the search term, required for 'preceeding/separated' check which is
  2232. executed directly on 'line' further below in censor_aux(). Eg:
  2233. sshit -> match the 2nd s and return it as position, not the 1st.
  2234. Otherwise, "this shit" -> "thisshit" -> the first s and the h would
  2235. be separated by a space in 'line' and therefore trigger the nonswear
  2236. special check. */
  2237. i = 0;
  2238. while (bufl[i]) {
  2239. j = 0;
  2240. add = 0; /* track duplicte chars */
  2241. #ifdef GET_MOST_DELAYED_MATCH
  2242. /* if we already got a match and the test of the upfollowing
  2243. position is negative, take that match, since we still want
  2244. to get all occurances eventually, not just the last one. */
  2245. if (bufs[j] != bufl[i + j + add] && best) return best;
  2246. #endif
  2247. while (bufs[j] == bufl[i + j + add]) {
  2248. if (bufs[j + 1] == '\0') {
  2249. *eff_len = j + add + 1;
  2250. #ifndef GET_MOST_DELAYED_MATCH
  2251. return &line[i]; /* FOUND */
  2252. #else
  2253. best = &line[i];
  2254. break;
  2255. #endif
  2256. }
  2257. j++;
  2258. /* end of line? */
  2259. if (bufl[i + j + add] == '\0')
  2260. #ifndef GET_MOST_DELAYED_MATCH
  2261. return (char*)NULL; /* NOT FOUND */
  2262. #else
  2263. return best;
  2264. #endif
  2265. /* reduce duplicate chars */
  2266. if (bufs[j] != bufl[i + j + add]) {
  2267. if (bufs[j - 1] == bufl[i + j + add])
  2268. add++;
  2269. }
  2270. }
  2271. /* NOT FOUND so far */
  2272. i++;
  2273. }
  2274. #ifndef GET_MOST_DELAYED_MATCH
  2275. return (char*)NULL; /* NOT FOUND */
  2276. #else
  2277. return best;
  2278. #endif
  2279. }
  2280. /* Censor swear words while keeping good words, and determining punishment level */
  2281. #define EXEMPT_BROKEN_SWEARWORDS /* don't 'recognize' swear words that are broken up into 'innocent' parts */
  2282. #define HIGHLY_EFFECTIVE_CENSOR /* strip all kinds of non-alpha chars too? */
  2283. #define CENSOR_PH_TO_F /* (slightly picky) convert ph to f ?*/
  2284. #define REDUCE_DUPLICATE_H /* (slightly picky) reduce multiple h to just one? */
  2285. #define REDUCE_H_CONSONANT /* (slightly picky) drop h before consonants? */
  2286. static int censor_aux(char *buf, char *lcopy, int *c, bool leet, bool max_reduce) {
  2287. int i, j, k, offset, cc[MSG_LEN], pos, eff_len;
  2288. char line[MSG_LEN];
  2289. char *word, l0, l1, l2, l3;
  2290. int level = 0;
  2291. /* create working copies */
  2292. strcpy(line, buf);
  2293. for (i = 0; !i || c[i]; i++) cc[i] = c[i];
  2294. cc[i] = 0;
  2295. /* replace certain non-alpha chars by alpha chars (leet speak detection)? */
  2296. if (leet) {
  2297. bool is_num = FALSE, prev_num;
  2298. i = 0;
  2299. while (lcopy[i]) {
  2300. prev_num = is_num;
  2301. is_num = FALSE;
  2302. switch (lcopy[i]) {
  2303. case '@': lcopy[i] = 'a'; break;
  2304. case '<': lcopy[i] = 'c'; break;
  2305. case '!': lcopy[i] = 'i'; break;
  2306. case '|': lcopy[i] = 'i'; break;
  2307. // case '(': lcopy[i] = 'c'; break;
  2308. // case ')': lcopy[i] = 'i'; break;
  2309. // case '/': lcopy[i] = 'i'; break;
  2310. // case '\\': lcopy[i] = 'i'; break;
  2311. case '$': lcopy[i] = 's'; break;
  2312. case '+': lcopy[i] = 't'; break;
  2313. case '1': lcopy[i] = 'i'; is_num = TRUE; break;
  2314. case '3': lcopy[i] = 'e'; is_num = TRUE; break;
  2315. case '4': lcopy[i] = 'a'; is_num = TRUE; break;
  2316. case '5': lcopy[i] = 's'; is_num = TRUE; break;
  2317. case '7': lcopy[i] = 't'; is_num = TRUE; break;
  2318. case '8': lcopy[i] = 'b'; is_num = TRUE; break;
  2319. case '0': lcopy[i] = 'o'; is_num = TRUE; break;
  2320. #ifdef HIGHLY_EFFECTIVE_CENSOR
  2321. /* hack: Actually _counter_ the capabilities of highly-effective
  2322. censoring being done further below after this. Reason:
  2323. Catch numerical expressions that probably aren't l33t sp34k,
  2324. such as "4.5", "4,5" or "4/5" etc.
  2325. Exact rule: <number><inconspicuous non-alphanum char><number> = allowed ->
  2326. Replace <inc. non-alphanum char> by inconspicuous alpha char. */
  2327. default:
  2328. /* inconspicuous non-alphanum char? */
  2329. if (prev_num &&
  2330. ((lcopy[i] < 'a' || lcopy[i] > 'z') && (lcopy[i] < '0' || lcopy[i] > '9')) &&
  2331. lcopy[i + 1] >= '0' && lcopy[i + 1] <= '9')
  2332. /* replace by, say 'x' (harmless^^) (Note: Capital character doesn't work, gets filtered out futher below */
  2333. lcopy[i] = 'x';
  2334. break;
  2335. #endif
  2336. }
  2337. line[cc[i]] = lcopy[i];
  2338. i++;
  2339. }
  2340. }
  2341. #ifdef REDUCE_H_CONSONANT
  2342. /* reduce 'h' before consonant */
  2343. //TODO: do HIGHLY_EFFECTIVE_CENSOR first probably
  2344. i = j = 0;
  2345. while (lcopy[j]) {
  2346. if (lcopy[j] == 'h' &&
  2347. lcopy[j + 1] != '\0' &&
  2348. lcopy[j + 1] != 'a' &&
  2349. lcopy[j + 1] != 'e' &&
  2350. lcopy[j + 1] != 'i' &&
  2351. lcopy[j + 1] != 'o' &&
  2352. lcopy[j + 1] != 'u' &&
  2353. lcopy[j + 1] != 'y'
  2354. && lcopy[j + 1] >= 'a' && lcopy[j + 1] <= 'z' /*TODO drop this, see 'TODO' above*/
  2355. ) {
  2356. j++;
  2357. }
  2358. /* build index map for stripped string */
  2359. cc[i] = cc[j];
  2360. lcopy[i] = lcopy[j];
  2361. i++;
  2362. j++;
  2363. }
  2364. lcopy[i] = '\0';
  2365. cc[i] = 0;
  2366. /* reduce 'h' after consonant except for c or s */
  2367. //TODO: do HIGHLY_EFFECTIVE_CENSOR first probably
  2368. i = j = 1;
  2369. if (lcopy[0])
  2370. while (lcopy[j]) {
  2371. if (lcopy[j] == 'h' &&
  2372. lcopy[j - 1] != 'c' &&
  2373. lcopy[j - 1] != 's' &&
  2374. lcopy[j - 1] != 'a' &&
  2375. lcopy[j - 1] != 'e' &&
  2376. lcopy[j - 1] != 'i' &&
  2377. lcopy[j - 1] != 'o' &&
  2378. lcopy[j - 1] != 'u'
  2379. && lcopy[j - 1] >= 'a' && lcopy[j - 1] <= 'z' /*TODO drop this, see 'TODO' above*/
  2380. ) {
  2381. j++;
  2382. continue;
  2383. }
  2384. /* build index map for stripped string */
  2385. cc[i] = cc[j];
  2386. lcopy[i] = lcopy[j];
  2387. i++;
  2388. j++;
  2389. }
  2390. lcopy[i] = '\0';
  2391. cc[i] = 0;
  2392. #endif
  2393. #ifdef HIGHLY_EFFECTIVE_CENSOR
  2394. /* check for non-alpha chars and _drop_ them (!) */
  2395. i = j = 0;
  2396. while (lcopy[j]) {
  2397. if ((lcopy[j] < 'a' || lcopy[j] > 'z') &&
  2398. lcopy[j] != 'Z') {
  2399. j++;
  2400. continue;
  2401. }
  2402. /* modify index map for stripped string */
  2403. cc[i] = cc[j];
  2404. lcopy[i] = lcopy[j];
  2405. i++;
  2406. j++;
  2407. }
  2408. lcopy[i] = '\0';
  2409. #endif
  2410. /* reduce repeated chars (>3 for consonants, >2 for vowel) */
  2411. i = j = 0;
  2412. while (lcopy[j]) {
  2413. /* paranoia (if HIGHLY_EFFECTIVE_CENSOR is enabled) */
  2414. if (lcopy[j] < 'a' || lcopy[j] > 'z') {
  2415. cc[i] = cc[j];
  2416. lcopy[i] = lcopy[j];
  2417. i++;
  2418. j++;
  2419. continue;
  2420. }
  2421. /* reduce any char repetition and re-check for swear words */
  2422. if (max_reduce) {
  2423. if (lcopy[j + 1] == lcopy[j]) {
  2424. j++;
  2425. continue;
  2426. }
  2427. } else switch (lcopy[j]) {
  2428. case 'a': case 'e': case 'i': case 'o': case 'u': case 'y':
  2429. if (lcopy[j + 1] == lcopy[j] &&
  2430. lcopy[j + 2] == lcopy[j]) {
  2431. j++;
  2432. continue;
  2433. }
  2434. default:
  2435. if (lcopy[j + 1] == lcopy[j] &&
  2436. lcopy[j + 2] == lcopy[j] &&
  2437. lcopy[j + 3] == lcopy[j]) {
  2438. j++;
  2439. continue;
  2440. }
  2441. break;
  2442. }
  2443. /* modify index map for reduced string */
  2444. cc[i] = cc[j];
  2445. lcopy[i] = lcopy[j];
  2446. i++;
  2447. j++;
  2448. }
  2449. /* check for swear words and censor them */
  2450. for (i = 0; swear[i].word[0]; i++) {
  2451. offset = 0;
  2452. /* check for multiple occurrances of this swear word */
  2453. while ((word = censor_strstr(lcopy + offset, swear[i].word, &eff_len))) {
  2454. pos = word - lcopy;
  2455. l0 = tolower(line[cc[pos]]);
  2456. l1 = l2 = l3 = 0; //kill compiler warnings
  2457. if (cc[pos] >= 1) l1 = tolower(line[cc[pos] - 1]);
  2458. if (cc[pos] >= 2) {
  2459. l2 = tolower(line[cc[pos] - 2]);
  2460. /* catch & dismiss colour codes */
  2461. if (l2 == '\377') l1 = 'Y'; /* 'disable' char */
  2462. }
  2463. if (cc[pos] >= 3) {
  2464. l3 = tolower(line[cc[pos] - 3]);
  2465. /* catch & dismiss colour codes */
  2466. if (l3 == '\377') l2 = 'Y'; /* 'disable' char */
  2467. }
  2468. /* prevent checking the same occurance repeatedly */
  2469. offset = pos + 1;
  2470. #ifdef EXEMPT_BROKEN_SWEARWORDS
  2471. /* hm, maybe don't track swear words if proceeded and postceeded by some other letters
  2472. and separated by spaces inside it -- and if those nearby letters aren't the same letter,
  2473. if someone just duplicates it like 'sshitt' */
  2474. /* check for swear-word-preceding non-duplicate alpha char */
  2475. if (cc[pos] > 0 &&
  2476. l1 >= 'a' && l1 <= 'z' &&
  2477. (l1 != l0 || strlen(swear[i].word) <= 3)) {
  2478. /* special treatment for swear words of <= 3 chars length: */
  2479. if (strlen(swear[i].word) <= 3) {
  2480. #if 0 /* softened this up, see below */
  2481. /* if there's UP TO 2 other chars before it or exactly 1 non-duplicate char, it's exempt.
  2482. (for more leading chars, nonswear has to be used.) */
  2483. if (cc[pos] == 1 && l1 >= 'a' && l1 <= 'z' && l1 != l0) continue;
  2484. if (cc[pos] == 2) {
  2485. if (l1 >= 'a' && l1 <= 'z' && l2 >= 'a' && l2 <= 'z' &&
  2486. (l0 != l1 || l0 != l2 || l1 != l2)) continue;
  2487. /* also test for only 1 leading alpha char */
  2488. if ((l2 < 'a' || l2 > 'z') &&
  2489. l1 >= 'a' && l1 <= 'z' && l1 != l0) continue;
  2490. }
  2491. if (cc[pos] >= 3) {
  2492. if ((l3 < 'a' || l3 > 'z') &&
  2493. l1 >= 'a' && l1 <= 'z' && l2 >= 'a' && l2 <= 'z' &&
  2494. (l0 != l1 || l0 != l2 || l1 != l2)) continue;
  2495. /* also test for only 1 leading alpha char */
  2496. if ((l2 < 'a' || l2 > 'z') &&
  2497. l1 >= 'a' && l1 <= 'z' && l1 != l0) continue;
  2498. }
  2499. /* if there's no char before it but 2 other chars after it or 1 non-dup after it, it's exempt. */
  2500. //TODO maybe - or just use nonswear for that
  2501. #else
  2502. /* if there's at least 2 other chars before it, which aren't both duplicates, or
  2503. if there's exactly 1 non-duplicate char before it, it's exempt. */
  2504. if (cc[pos] == 1 && l1 >= 'a' && l1 <= 'z' && l1 != l0) continue;
  2505. if (cc[pos] >= 2) {
  2506. if (l1 >= 'a' && l1 <= 'z' && l2 >= 'a' && l2 <= 'z' &&
  2507. (l0 != l1 || l0 != l2 || l1 != l2)) continue;
  2508. /* also test for only 1 leading alpha char */
  2509. if ((l2 < 'a' || l2 > 'z') &&
  2510. l1 >= 'a' && l1 <= 'z' && l1 != l0) continue;
  2511. }
  2512. /* if there's no char before it but 2 other chars after it or 1 non-dup after it, it's exempt. */
  2513. //TODO maybe - or just use nonswear for that
  2514. #endif
  2515. }
  2516. /* check that the swear word occurance was originally non-continuous, ie separated by space etc.
  2517. (if this is FALSE then this is rather a case for nonswearwords.txt instead.) */
  2518. for (j = cc[pos]; j < cc[pos + strlen(swear[i].word) - 1]; j++) {
  2519. if (tolower(line[j]) < 'a' || tolower(line[j] > 'z')) {
  2520. /* heuristical non-swear word found! */
  2521. break;
  2522. }
  2523. }
  2524. /* found? */
  2525. if (j < cc[pos + strlen(swear[i].word) - 1]) {
  2526. /* prevent it from getting tested for swear words */
  2527. continue;
  2528. }
  2529. }
  2530. #endif
  2531. /* we can skip ahead */
  2532. offset = pos + strlen(swear[i].word);
  2533. #if 0
  2534. /* censor it! */
  2535. for (j = 0; j < eff_len); j++) {
  2536. line[cc[pos + j]] = buf[cc[pos + j]] = '*';
  2537. lcopy[pos + j] = '*';
  2538. }
  2539. #else
  2540. /* actually censor separator chars too, just so it looks better ;) */
  2541. for (j = 0; j < eff_len - 1; j++) {
  2542. for (k = cc[pos + j]; k <= cc[pos + j + 1]; k++)
  2543. line[k] = buf[k] = '*';
  2544. /* MUST be disabled or interferes with detection overlaps: */
  2545. /* for processing lcopy in a while loop instead of just 'if'
  2546. -- OBSOLETE ACTUALLY (thanks to 'offset')? */
  2547. // lcopy[pos + j] = '*';
  2548. }
  2549. /* see right above - MUST be disabled: */
  2550. // lcopy[pos + j] = '*';
  2551. #endif
  2552. level = MAX(level, swear[i].level);
  2553. }
  2554. }
  2555. return(level);
  2556. }
  2557. /* 433+ $p34k: Try to translate certain numbers and symbols to letters? */
  2558. //#define CENSOR_LEET
  2559. static int censor(char *line) {
  2560. int i, j, im, jm, cc[MSG_LEN], offset;
  2561. char lcopy[MSG_LEN], lcopy2[MSG_LEN];
  2562. char tmp1[MSG_LEN], tmp2[MSG_LEN], tmp3[MSG_LEN], tmp4[MSG_LEN];
  2563. char *word;
  2564. strcpy(lcopy, line);
  2565. /* convert to lower case */
  2566. i = 0;
  2567. while (lcopy[i]) {
  2568. lcopy[i] = tolower(lcopy[i]);
  2569. i++;
  2570. }
  2571. /* strip colour codes and initialize index map (cc[]) at that */
  2572. i = j = 0;
  2573. while (lcopy[j]) {
  2574. if (lcopy[j] == '\377') {
  2575. j++;
  2576. if (lcopy[j]) j++;
  2577. continue;
  2578. }
  2579. /* initially build index map for stripped string */
  2580. cc[i] = j;
  2581. lcopy[i] = lcopy[j];
  2582. i++;
  2583. j++;
  2584. }
  2585. lcopy[i] = '\0';
  2586. cc[i] = 0;
  2587. #ifdef CENSOR_PH_TO_F
  2588. /* reduce ph to f */
  2589. i = j = 0;
  2590. while (lcopy[j]) {
  2591. if (lcopy[j] == 'p' && lcopy[j + 1] == 'h') {
  2592. cc[i] = cc[j];
  2593. lcopy[i] = 'f';
  2594. i++;
  2595. j += 2;
  2596. continue;
  2597. }
  2598. /* build index map for stripped string */
  2599. cc[i] = cc[j];
  2600. lcopy[i] = lcopy[j];
  2601. i++;
  2602. j++;
  2603. }
  2604. lcopy[i] = '\0';
  2605. cc[i] = 0;
  2606. #endif
  2607. #ifdef REDUCE_DUPLICATE_H
  2608. /* reduce hh to h */
  2609. i = j = 0;
  2610. while (lcopy[j]) {
  2611. if (lcopy[j] == 'h' && lcopy[j + 1] == 'h') {
  2612. j++;
  2613. continue;
  2614. }
  2615. /* build index map for stripped string */
  2616. cc[i] = cc[j];
  2617. lcopy[i] = lcopy[j];
  2618. i++;
  2619. j++;
  2620. }
  2621. lcopy[i] = '\0';
  2622. cc[i] = 0;
  2623. #endif
  2624. /* check for legal words first */
  2625. //TODO: could be moved into censor_aux and after leet speek conversion, to allow leet speeking of non-swear words (eg "c00k")
  2626. strcpy(lcopy2, lcopy); /* use a 'working copy' to allow _overlapping_ nonswear words */
  2627. for (i = 0; nonswear[i][0]; i++) {
  2628. offset = 0;
  2629. /* check for multiple occurrances of this nonswear word */
  2630. while ((word = strstr(lcopy + offset, nonswear[i]))) {
  2631. /* prevent checking the same occurance repeatedly */
  2632. offset = word - lcopy + strlen(nonswear[i]);
  2633. /* prevent it from getting tested for swear words */
  2634. for (j = 0; j < strlen(nonswear[i]); j++)
  2635. lcopy2[(word - lcopy) + j] = 'Z';
  2636. }
  2637. }
  2638. /* perform 2x2 more 'parallel' tests */
  2639. strcpy(tmp1, line);
  2640. strcpy(tmp2, line);
  2641. strcpy(tmp3, line);
  2642. strcpy(tmp4, line);
  2643. strcpy(lcopy, lcopy2);
  2644. i = censor_aux(tmp1, lcopy, cc, FALSE, FALSE); /* continue with normal check */
  2645. strcpy(lcopy, lcopy2);
  2646. #ifdef CENSOR_LEET
  2647. j = censor_aux(tmp2, lcopy, cc, TRUE, FALSE); /* continue with leet speek check */
  2648. strcpy(lcopy, lcopy2);
  2649. #else
  2650. j = 0;
  2651. #endif
  2652. im = censor_aux(tmp3, lcopy, cc, FALSE, TRUE); /* continue with normal check */
  2653. strcpy(lcopy, lcopy2);
  2654. #ifdef CENSOR_LEET
  2655. jm = censor_aux(tmp4, lcopy, cc, TRUE, TRUE); /* continue with leet speek check */
  2656. #else
  2657. jm = 0;
  2658. #endif
  2659. /* combine all censored characters */
  2660. for (offset = 0; tmp1[offset]; offset++)
  2661. if (tmp1[offset] == '*') line[offset] = '*';
  2662. #ifdef CENSOR_LEET
  2663. for (offset = 0; tmp2[offset]; offset++)
  2664. if (tmp2[offset] == '*') line[offset] = '*';
  2665. #endif
  2666. for (offset = 0; tmp3[offset]; offset++)
  2667. if (tmp3[offset] == '*') line[offset] = '*';
  2668. #ifdef CENSOR_LEET
  2669. for (offset = 0; tmp4[offset]; offset++)
  2670. if (tmp4[offset] == '*') line[offset] = '*';
  2671. #endif
  2672. /* return 'worst' result */
  2673. if (j > i) i = j;
  2674. if (im > i) i = im;
  2675. if (jm > i) i = jm;
  2676. return i;
  2677. }
  2678. #endif
  2679. /*
  2680. * A message prefixed by a player name is sent only to that player.
  2681. * Otherwise, it is sent to everyone.
  2682. */
  2683. /*
  2684. * This function is hacked *ALOT* to add extra-commands w/o
  2685. * client change. - Jir -
  2686. *
  2687. * Yeah. totally.
  2688. *
  2689. * Muted players can't talk now (player_type.muted-- can be enabled
  2690. * through /mute <name> and disabled through /unmute <name>).
  2691. * - the_sandman
  2692. */
  2693. static void player_talk_aux(int Ind, char *message)
  2694. {
  2695. int i, len, target = 0;
  2696. char search[MSG_LEN], sender[MAX_CHARS];
  2697. char message2[MSG_LEN];
  2698. player_type *p_ptr = NULL, *q_ptr;
  2699. char *colon;
  2700. bool me = FALSE, log = TRUE;
  2701. char c_n = 'B', c_b = 'B'; /* colours of sender name and of brackets (unused atm) around this name */
  2702. int mycolor = 0;
  2703. bool admin = FALSE;
  2704. bool broadcast = FALSE;
  2705. #ifdef TOMENET_WORLDS
  2706. char tmessage[MSG_LEN]; /* TEMPORARY! We will not send the name soon */
  2707. #endif
  2708. if (!Ind) {
  2709. console_talk_aux(message);
  2710. return;
  2711. }
  2712. /* Get sender's name */
  2713. p_ptr = Players[Ind];
  2714. /* Get player name */
  2715. strcpy(sender, p_ptr->name);
  2716. admin = is_admin(p_ptr);
  2717. /* Default to no search string */
  2718. strcpy(search, "");
  2719. /* Look for a player's name followed by a colon */
  2720. /* tBot's stuff */
  2721. /* moved here to allow tbot to see fake pvt messages. -Molt */
  2722. strncpy(last_chat_owner, sender, NAME_LEN);
  2723. strncpy(last_chat_line, message, MSG_LEN);
  2724. /* do exec_lua() not here instead of in dungeon.c - mikaelh */
  2725. /* '-:' at beginning of message sends to normal chat, cancelling special chat modes - C. Blue */
  2726. if (strlen(message) >= 4 && message[1] == ':' && message[2] == '-' && message[3] == ':')
  2727. message += 4;
  2728. /* Catch this case too anyway, just for comfort if someone uses fixed macros for -: */
  2729. else if (strlen(message) >= 2 && message[0] == '-' && message[1] == ':')
  2730. message += 2;
  2731. /* hack: preparse for private chat target, and if found
  2732. then strip chat mode prefixes to switch to private chat mode - C. Blue */
  2733. /* Form a search string if we found a colon */
  2734. if (strlen(message) > 4 && message[1] == ':' && message[2] != ':' &&
  2735. (message[0] == '!' || message[0] == '#' || message[0] == '$')
  2736. && (colon = strchr(message + 3, ':'))) {
  2737. /* Copy everything up to the colon to the search string */
  2738. strncpy(search, message + 2, colon - message - 2);
  2739. search[colon - message - 2] = '\0';
  2740. /* Acquire length of search string */
  2741. len = strlen(search);
  2742. /* Look for a recipient who matches the search string */
  2743. if (len) {
  2744. struct rplist *w_player;
  2745. /* NAME_LOOKUP_LOOSE DESPERATELY NEEDS WORK */
  2746. target = name_lookup_loose_quiet(Ind, search, TRUE, TRUE);
  2747. if (target) {
  2748. /* strip leading chat mode prefix,
  2749. pretend that it's a private message instead */
  2750. message += 2;
  2751. }
  2752. #ifdef TOMENET_WORLDS
  2753. else if (cfg.worldd_privchat) {
  2754. w_player = world_find_player(search, 0);
  2755. if (w_player) {
  2756. /* strip leading chat mode prefix,
  2757. pretend that it's a private message instead */
  2758. message += 2;
  2759. }
  2760. }
  2761. #endif
  2762. }
  2763. /* erase our traces */
  2764. search[0] = '\0';
  2765. len = 0;
  2766. }
  2767. colon = strchr(message, ':');
  2768. /* Ignore "smileys" or URL */
  2769. // if (colon && strchr(")(-/:", colon[1]))
  2770. /* (C. Blue) changing colon parsing. :: becomes
  2771. textual : - otherwise : stays control char */
  2772. if (colon) {
  2773. bool smiley = FALSE;
  2774. /* no double-colon '::' smileys inside possible item inscriptions */
  2775. char *bracer = strchr(message, '{');
  2776. bool maybe_inside_inscription = bracer != NULL && bracer < colon;
  2777. /* if another colon followed this one then
  2778. it was not meant to be a control char */
  2779. switch (colon[1]) {
  2780. /* accept these chars for smileys, but only if the colon is either first in the line or stands after a SPACE,
  2781. otherwise it is to expect that someone tried to write to party/privmsg */
  2782. case '(': case ')':
  2783. case '[': case ']':
  2784. case '{': case '}':
  2785. /* staircases, so cannot be used for smileys here -> case '<': case '>': */
  2786. case '\\': case '|':
  2787. case 'p': case 'P': case 'o': case 'O':
  2788. if (message == colon || colon[-1] == ' ' || colon[-1] == '>' || /* >:) -> evil smiley */
  2789. ((message == colon - 1) && (colon[-1] != '!') && (colon[-1] != '#') && (colon[-1] != '%') && (colon[-1] != '$') && (colon[-1] != '+'))) /* <- party names must be at least 2 chars then */
  2790. colon = NULL; /* the check is mostly important for '(' */
  2791. break;
  2792. case '-':
  2793. if (message == colon || colon[-1] == ' ' || colon[-1] == '>' || /* here especially important: '-' often is for numbers/recall depth */
  2794. ((message == colon - 1) && (colon[-1] != '!') && (colon[-1] != '#') && (colon[-1] != '%') && (colon[-1] != '$') && (colon[-1] != '+'))) /* <- party names must be at least 2 chars then */
  2795. if (!strchr("123456789", *(colon + 2))) colon = NULL;
  2796. break;
  2797. case '/':
  2798. /* only accept / at the end of a chat message */
  2799. if ('\0' == *(colon + 2)) colon = NULL;
  2800. /* or it might be a http:// style link */
  2801. else if ('/' == *(colon + 2)) colon = NULL;
  2802. break;
  2803. case ':':
  2804. /* remove the 1st colon found, .. */
  2805. /* always if there's no chat-target in front of the double-colon: */
  2806. if (message == colon || colon[-1] == ' ') {
  2807. i = (int) (colon - message);
  2808. do message[i] = message[i+1];
  2809. while(message[i++]!='\0');
  2810. colon = NULL;
  2811. break;
  2812. }
  2813. /* new hack: ..but only if the previous two chars aren't !: (party chat),
  2814. and if it's appearently meant to be a smiley. */
  2815. if ((colon - message == 1) && (colon[-1]=='!' || colon[-1]=='#' || colon[-1]=='%' || colon[-1]=='$' || colon[-1]=='+'))
  2816. switch (*(colon + 2)) {
  2817. case '(': case ')':
  2818. case '[': case ']':
  2819. case '{': case '}':
  2820. case '<': case '>':
  2821. case '-': case '|':
  2822. case 'p': case 'P': case 'o': case 'O': case 'D':
  2823. smiley = !maybe_inside_inscription; break; }
  2824. /* check for smiley at end of the line */
  2825. if ((message + strlen(message) - colon >= 3) &&
  2826. (message + strlen(message) - colon <= 4)) // == 3 for 2-letter-smileys only.
  2827. // if ((*(colon + 2)) && !(*(colon + 3)))
  2828. switch (*(colon + 2)) {
  2829. case '(': case ')':
  2830. case '[': case ']':
  2831. case '{': case '}':
  2832. case '<': case '>':
  2833. case '-': case '/':
  2834. case '\\': case '|':
  2835. case 'p': case 'P': case 'o': case 'O': case 'D':
  2836. smiley = !maybe_inside_inscription; break; }
  2837. if (smiley) break;
  2838. /* Pretend colon wasn't there */
  2839. i = (int) (colon - message);
  2840. do message[i] = message[i+1];
  2841. while(message[i++]!='\0');
  2842. colon = NULL;
  2843. break;
  2844. case '\0':
  2845. /* if colon is last char in the line, it's not a priv/party msg. */
  2846. #if 0 /* disabled this 'feature', might be more convenient - C. Blue */
  2847. colon = NULL;
  2848. #else
  2849. if (colon[-1]!='!' && colon[-1]!='#' && colon[-1]!='%' && colon[-1]!='$' && colon[-1]!='+')
  2850. colon = NULL;
  2851. #endif
  2852. break;
  2853. }
  2854. }
  2855. /* don't log spammy slash commands */
  2856. if (prefix(message, "/untag ")) log = FALSE;
  2857. /* no big brother */
  2858. // if(cfg.log_u && (!colon || message[0] != '#' || message[0] != '/')){ /* message[0] != '#' || message[0] != '/' is always true -> big brother mode - mikaelh */
  2859. if (cfg.log_u && (!colon) && log) {
  2860. /* Shorten multiple identical messages to prevent log file spam,
  2861. eg recall rod activation attempts. - Exclude admins. */
  2862. if (admin)
  2863. s_printf("[%s] %s\n", sender, message);
  2864. else if (strcmp(message, p_ptr->last_chat_line)) {
  2865. if (p_ptr->last_chat_line_cnt) {
  2866. s_printf("[%s (x%d)]\n", sender, p_ptr->last_chat_line_cnt + 1);
  2867. p_ptr->last_chat_line_cnt = 0;
  2868. }
  2869. s_printf("[%s] %s\n", sender, message);
  2870. /* Keep track of repeating chat lines to avoid log file spam (slash commands like '/rec' mostly) */
  2871. strncpy(p_ptr->last_chat_line, message, MSG_LEN - 1);
  2872. p_ptr->last_chat_line[MSG_LEN - 1] = 0;
  2873. } else p_ptr->last_chat_line_cnt++;
  2874. }
  2875. /* Special - shutdown command (for compatibility) */
  2876. if (prefix(message, "@!shutdown") && admin) {
  2877. /*world_reboot();*/
  2878. shutdown_server();
  2879. return;
  2880. }
  2881. if (message[0] == '/' ){
  2882. if (!strncmp(message, "/me ", 4)) me = TRUE;
  2883. else if (!strncmp(message, "/broadcast ", 11)) broadcast = TRUE;
  2884. else {
  2885. do_slash_cmd(Ind, message); /* add check */
  2886. return;
  2887. }
  2888. }
  2889. #ifndef ARCADE_SERVER
  2890. if (!colon) p_ptr->msgcnt++; /* !colon -> only prevent spam if not in party/private chat */
  2891. if (p_ptr->msgcnt > 12) {
  2892. time_t last = p_ptr->msg;
  2893. time(&p_ptr->msg);
  2894. if (p_ptr->msg - last < 6) {
  2895. p_ptr->spam++;
  2896. switch (p_ptr->spam) {
  2897. case 1:
  2898. msg_print(Ind, "\377yPlease don't spam the server");
  2899. break;
  2900. case 3:
  2901. case 4:
  2902. msg_print(Ind, "\374\377rWarning! this behaviour is unacceptable!");
  2903. break;
  2904. case 5:
  2905. p_ptr->chp = -3;
  2906. strcpy(p_ptr->died_from, "hypoxia");
  2907. p_ptr->spam = 1;
  2908. p_ptr->deathblow = 0;
  2909. player_death(Ind);
  2910. return;
  2911. }
  2912. }
  2913. if (p_ptr->msg-last > 240 && p_ptr->spam) p_ptr->spam--;
  2914. p_ptr->msgcnt = 0;
  2915. }
  2916. if (p_ptr->spam > 1 || p_ptr->muted) return;
  2917. #endif
  2918. process_hooks(HOOK_CHAT, "d", Ind);
  2919. if (++p_ptr->talk > 10) {
  2920. imprison(Ind, 30, "talking too much.");
  2921. return;
  2922. }
  2923. for (i = 1; i <= NumPlayers; i++) {
  2924. if (Players[i]->conn == NOT_CONNECTED) continue;
  2925. Players[i]->talk = 0;
  2926. }
  2927. /* Special function '!:' at beginning of message sends to own party - sorry for hack, C. Blue */
  2928. // if ((strlen(message) >= 1) && (message[0] == ':') && (!colon) && (p_ptr->party))
  2929. if ((strlen(message) >= 2) && (message[0] == '!') && (message[1] == ':') && (colon) && (p_ptr->party)) {
  2930. target = p_ptr->party;
  2931. #if 1 /* No private chat for invalid accounts ? */
  2932. if (p_ptr->inval) {
  2933. msg_print(Ind, "\377yYour account is not valid, wait for an admin to validate it.");
  2934. return;
  2935. }
  2936. #endif
  2937. /* Send message to target party */
  2938. if (p_ptr->mutedchat < 2) {
  2939. #ifdef GROUP_CHAT_NOCLUTTER
  2940. party_msg_format_ignoring(Ind, target, "\375\377%c[(P) %s] %s", COLOUR_CHAT_PARTY, sender, message + 2);
  2941. #else
  2942. party_msg_format_ignoring(Ind, target, "\375\377%c[%s:%s] %s", COLOUR_CHAT_PARTY, parties[target].name, sender, message + 2);
  2943. #endif
  2944. // party_msg_format_ignoring(Ind, target, "\375\377%c[%s:%s] %s", COLOUR_CHAT_PARTY, parties[target].name, sender, message + 1);
  2945. }
  2946. /* Done */
  2947. return;
  2948. }
  2949. /* '#:' at beginning of message sends to dungeon level - C. Blue */
  2950. if ((strlen(message) >= 2) && (message[0] == '#') && (message[1] == ':') && (colon)) {
  2951. #if 1 /* No private chat for invalid accounts ? */
  2952. if (p_ptr->inval) {
  2953. msg_print(Ind, "\377yYour account is not valid, wait for an admin to validate it.");
  2954. return;
  2955. }
  2956. #endif
  2957. if (!p_ptr->wpos.wz) {
  2958. #if 0
  2959. msg_print(Ind, "You aren't in a dungeon or tower.");
  2960. #else /* Darkie's idea: */
  2961. if (*(message + 2)) {
  2962. censor_message = TRUE;
  2963. censor_length = strlen(message + 2);
  2964. msg_format_near(Ind, "\377%c%^s says: %s", COLOUR_CHAT, p_ptr->name, message + 2);
  2965. msg_format(Ind, "\377%cYou say: %s", COLOUR_CHAT, message + 2);
  2966. censor_message = FALSE;
  2967. handle_punish(Ind, censor_punish);
  2968. } else {
  2969. msg_format_near(Ind, "\377%c%s clears %s throat.", COLOUR_CHAT, p_ptr->name, p_ptr->male ? "his" : "her");
  2970. msg_format(Ind, "\377%cYou clear your throat.", COLOUR_CHAT);
  2971. }
  2972. #endif
  2973. return;
  2974. }
  2975. /* Send message to target floor */
  2976. if (p_ptr->mutedchat < 2) {
  2977. censor_message = TRUE;
  2978. censor_length = strlen(message + 2);
  2979. floor_msg_format_ignoring(Ind, &p_ptr->wpos, "\375\377%c[%s] %s", COLOUR_CHAT_LEVEL, sender, message + 2);
  2980. censor_message = FALSE;
  2981. handle_punish(Ind, censor_punish);
  2982. }
  2983. /* Done */
  2984. return;
  2985. }
  2986. /* '%:' at the beginning sends to self - mikaelh */
  2987. if ((strlen(message) >= 2) && (message[0] == '%') && (message[1] == ':') && (colon)) {
  2988. /* Send message to self */
  2989. msg_format(Ind, "\377o<%%>\377w %s", message + 2);
  2990. /* Done */
  2991. return;
  2992. }
  2993. /* '+:' at beginning of message sends reply to last player who sent us a private msg - C. Blue */
  2994. if ((strlen(message) >= 2) && (message[0] == '+') && (message[1] == ':') && colon) {
  2995. #if 1 /* No private chat for invalid accounts ? */
  2996. if (p_ptr->inval) {
  2997. msg_print(Ind, "\377yYour account is not valid, wait for an admin to validate it.");
  2998. return;
  2999. }
  3000. #endif
  3001. /* Haven't received an initial private msg yet? */
  3002. if (!p_ptr->reply_name || !strlen(p_ptr->reply_name)) {
  3003. msg_print(Ind, "You haven't received any private message to reply to yet.");
  3004. return;
  3005. }
  3006. if (p_ptr->mutedchat == 2) return;
  3007. /* Forge private message */
  3008. strcpy(message2, p_ptr->reply_name);
  3009. strcat(message2, message + 1);
  3010. strcpy(message, message2);
  3011. colon = message + strlen(p_ptr->reply_name);
  3012. /* Continue with forged private message */
  3013. }
  3014. /* '$:' at beginning of message sends to guild - C. Blue */
  3015. if ((strlen(message) >= 2) && (message[0] == '$') && (message[1] == ':') && (colon) && (p_ptr->guild)) {
  3016. #if 1 /* No private chat for invalid accounts ? */
  3017. if (p_ptr->inval) {
  3018. msg_print(Ind, "\377yYour account is not valid, wait for an admin to validate it.");
  3019. return;
  3020. }
  3021. #endif
  3022. /* Send message to guild party */
  3023. if (p_ptr->mutedchat < 2) {
  3024. #ifdef GROUP_CHAT_NOCLUTTER
  3025. guild_msg_format(p_ptr->guild, "\375\377y[\377%c(G) %s\377y]\377%c %s", COLOUR_CHAT_GUILD, sender, COLOUR_CHAT_GUILD, message + 2);
  3026. #else
  3027. guild_msg_format(p_ptr->guild, "\375\377y[\377%c%s\377y:\377%c%s\377y]\377%c %s", COLOUR_CHAT_GUILD, guilds[p_ptr->guild].name, COLOUR_CHAT_GUILD, sender, COLOUR_CHAT_GUILD, message + 2);
  3028. #endif
  3029. }
  3030. /* Done */
  3031. return;
  3032. }
  3033. /* Form a search string if we found a colon */
  3034. if (colon) {
  3035. if (p_ptr->mutedchat == 2) return;
  3036. #if 1 /* No private chat for invalid accounts ? */
  3037. if (p_ptr->inval) {
  3038. msg_print(Ind, "\377yYour account is not valid, wait for an admin to validate it.");
  3039. return;
  3040. }
  3041. #endif
  3042. /* Copy everything up to the colon to the search string */
  3043. strncpy(search, message, colon - message);
  3044. /* Add a trailing NULL */
  3045. search[colon - message] = '\0';
  3046. } else if (p_ptr->mutedchat) return;
  3047. /* Acquire length of search string */
  3048. len = strlen(search);
  3049. /* Look for a recipient who matches the search string */
  3050. if (len) {
  3051. struct rplist *w_player;
  3052. /* NAME_LOOKUP_LOOSE DESPERATELY NEEDS WORK */
  3053. target = name_lookup_loose_quiet(Ind, search, TRUE, TRUE);
  3054. #ifdef TOMENET_WORLDS
  3055. if (!target && cfg.worldd_privchat) {
  3056. w_player = world_find_player(search, 0);
  3057. if (w_player) {
  3058. world_pmsg_send(p_ptr->id, p_ptr->name, w_player->name, colon + 1);
  3059. msg_format(Ind, "\375\377s[%s:%s] %s", p_ptr->name, w_player->name, colon + 1);
  3060. /* hack: assume that the target player will become the
  3061. one we want to 'reply' to, afterwards, if we don't
  3062. have a reply-to target yet. */
  3063. if ((!p_ptr->reply_name || !strlen(p_ptr->reply_name)))
  3064. strcpy(p_ptr->reply_name, w_player->name);
  3065. return;
  3066. }
  3067. }
  3068. #endif
  3069. /* Move colon pointer forward to next word */
  3070. /* no, this isn't needed and actually has annoying effects if you try to write smileys:
  3071. while (*colon && (isspace(*colon) || *colon == ':')) colon++; */
  3072. /* instead, this is sufficient: */
  3073. if (colon) colon++;
  3074. /* lookup failed */
  3075. if (!target) {
  3076. /* Bounce message to player who sent it */
  3077. // msg_format(Ind, "(no receipient for: %s)", colon);
  3078. #ifndef ARCADE_SERVER
  3079. msg_print(Ind, "(Cannot match desired recipient)");
  3080. #endif
  3081. /* Allow fake private msgs to be intercepted - Molt */
  3082. exec_lua(0, "chat_handler()");
  3083. /* Give up */
  3084. return;
  3085. }
  3086. }
  3087. /* Send to appropriate player */
  3088. if (len && target > 0) {
  3089. if (!check_ignore(target, Ind)) {
  3090. /* Set target player */
  3091. q_ptr = Players[target];
  3092. /* Remember sender, to be able to reply to him quickly */
  3093. #if 0
  3094. strcpy(q_ptr->reply_name, sender);
  3095. #else /* use his account name instead, since it's possible now */
  3096. if (!strcmp(sender, p_ptr->name)) strcpy(q_ptr->reply_name, p_ptr->accountname);
  3097. else strcpy(q_ptr->reply_name, sender);
  3098. #endif
  3099. /* Send message to target */
  3100. msg_format(target, "\375\377g[%s:%s] %s", sender, q_ptr->name, colon);
  3101. if ((q_ptr->page_on_privmsg ||
  3102. (q_ptr->page_on_afk_privmsg && q_ptr->afk)) &&
  3103. q_ptr->paging == 0)
  3104. q_ptr->paging = 1;
  3105. /* Also send back to sender */
  3106. if (target != Ind)
  3107. msg_format(Ind, "\375\377g[%s:%s] %s", sender, q_ptr->name, colon);
  3108. /* Only display this message once now - mikaelh */
  3109. if (q_ptr->afk && !player_list_find(p_ptr->afk_noticed, q_ptr->id)) {
  3110. msg_format(Ind, "\377o%s seems to be Away From Keyboard.", q_ptr->name);
  3111. player_list_add(&p_ptr->afk_noticed, q_ptr->id);
  3112. }
  3113. #if 0
  3114. /* hack: assume that the target player will become the
  3115. one we want to 'reply' to, afterwards, if we don't
  3116. have a reply-to target yet. */
  3117. if (!p_ptr->reply_name || !strlen(p_ptr->reply_name))
  3118. strcpy(p_ptr->reply_name, q_ptr->name);
  3119. #else
  3120. /* hack: assume that the target player will become the
  3121. one we want to 'reply' to, afterwards.
  3122. This might get somewhat messy if we're privchatting
  3123. to two players at the same time, but so would
  3124. probably the other variant above. That one stays
  3125. true to the '+:' definition given in the guide though,
  3126. while this one diverges a bit. */
  3127. #if 0
  3128. strcpy(p_ptr->reply_name, q_ptr->name);
  3129. #else /* use his account name instead, since it's possible now */
  3130. strcpy(p_ptr->reply_name, q_ptr->accountname);
  3131. #endif
  3132. #endif
  3133. exec_lua(0, "chat_handler()");
  3134. return;
  3135. } else {
  3136. /* Tell the sender */
  3137. msg_print(Ind, "(That player has ignored you)");
  3138. return;
  3139. }
  3140. }
  3141. /* Send to appropriate party */
  3142. if (len && target < 0) {
  3143. /* Can't send msg to party from 'outside' as non-admin */
  3144. if (p_ptr->party != 0 - target && !admin) {
  3145. msg_print(Ind, "You aren't in that party.");
  3146. return;
  3147. }
  3148. /* Send message to target party */
  3149. party_msg_format_ignoring(Ind, 0 - target, "\375\377%c[(P) %s] %s", COLOUR_CHAT_PARTY, sender, colon);
  3150. //party_msg_format_ignoring(Ind, 0 - target, "\375\377%c[%s:%s] %s", COLOUR_CHAT_PARTY, parties[0 - target].name, sender, colon);
  3151. /* Also send back to sender if not in that party */
  3152. if (!player_in_party(0 - target, Ind)) {
  3153. msg_format(Ind, "\375\377%c[%s:%s] %s",
  3154. COLOUR_CHAT_PARTY, parties[0 - target].name, sender, colon);
  3155. }
  3156. exec_lua(0, "chat_handler()");
  3157. /* Done */
  3158. return;
  3159. }
  3160. if (strlen(message) > 1) mycolor = (prefix(message, "}") && (color_char_to_attr(*(message + 1)) != -1)) ? 2 : 0;
  3161. if (!Ind) c_n = 'y';
  3162. /* Disabled this for now to avoid confusion. */
  3163. else if (mycolor) c_n = *(message + 1);
  3164. else {
  3165. /* Dungeon Master / Dungeon Wizard have their own colour now :) */
  3166. if (is_admin(p_ptr)) c_n = 'b';
  3167. else if (p_ptr->total_winner) c_n = 'v';
  3168. else if (p_ptr->ghost) c_n = 'r';
  3169. else if (p_ptr->mode & MODE_EVERLASTING) c_n = 'B';
  3170. else if (p_ptr->mode & MODE_PVP) c_n = COLOUR_MODE_PVP;
  3171. else if (p_ptr->mode & MODE_NO_GHOST) c_n = 'D';
  3172. else if (p_ptr->mode & MODE_HARD) c_n = 's';
  3173. else c_n = 'W'; /* normal mode */
  3174. if ((p_ptr->mode & MODE_HARD) && (p_ptr->mode & MODE_NO_GHOST))
  3175. c_b = 'r'; /* hellish mode */
  3176. else c_b = c_n;
  3177. }
  3178. /* Admins have exclusive colour - the_sandman */
  3179. if (c_n == 'b' && !admin) return;
  3180. censor_message = TRUE;
  3181. #ifdef TOMENET_WORLDS
  3182. if (broadcast) {
  3183. snprintf(tmessage, sizeof(tmessage), "\375\377r[\377%c%s\377r]\377%c %s", c_n, sender, COLOUR_CHAT, message + 11);
  3184. censor_length = strlen(message + 11);
  3185. } else if (!me) {
  3186. snprintf(tmessage, sizeof(tmessage), "\375\377%c[%s]\377%c %s", c_n, sender, COLOUR_CHAT, message + mycolor);
  3187. censor_length = strlen(message + mycolor);
  3188. } else {
  3189. /* Why not... */
  3190. if (strlen(message) > 4) mycolor = (prefix(&message[4], "}") && (color_char_to_attr(*(message + 5)) != -1)) ? 2 : 0;
  3191. else {
  3192. censor_message = FALSE;
  3193. return;
  3194. }
  3195. if (mycolor) c_n = message[5];
  3196. snprintf(tmessage, sizeof(tmessage), "\375\377%c[%s %s]", c_n, sender, message + 4 + mycolor);
  3197. censor_length = strlen(message + 4 + mycolor) + 1;
  3198. }
  3199. #if 0
  3200. #if 0
  3201. if ((broadcast && cfg.worldd_broadcast) || (!broadcast && cfg.worldd_pubchat))
  3202. && !(len && (target != 0) && !cfg.worldd_privchat)) /* privchat = to party or to person */
  3203. world_chat(p_ptr->id, tmessage); /* no ignores... */
  3204. #else
  3205. /* Incoming chat is now filtered instead of outgoing which allows IRC relay to get public chat messages from worldd - mikaelh */
  3206. world_chat(p_ptr->id, tmessage); /* no ignores... */
  3207. #endif
  3208. #else /* Remove current redundancy. Make worldd_pubchat decide if we broadcast all our chat out there or not. */
  3209. /* in case privchat wasn't handled above (because it's disabled),
  3210. exempt it here so we only process real chat/broadcasts */
  3211. if (!(!cfg.worldd_privchat && len && target != 0)) {
  3212. if (broadcast && cfg.worldd_broadcast) {
  3213. world_chat(0, tmessage); /* can't ignore */
  3214. } else if (!broadcast && cfg.worldd_pubchat) {
  3215. world_chat(p_ptr->id, tmessage);
  3216. }
  3217. }
  3218. #endif
  3219. for(i = 1; i <= NumPlayers; i++) {
  3220. q_ptr = Players[i];
  3221. if (!admin) {
  3222. if (check_ignore(i, Ind)) continue;
  3223. if (q_ptr->ignoring_chat) continue;
  3224. if (!broadcast && (p_ptr->limit_chat || q_ptr->limit_chat) &&
  3225. !inarea(&p_ptr->wpos, &q_ptr->wpos)) continue;
  3226. }
  3227. msg_print(i, tmessage);
  3228. }
  3229. #else
  3230. /* Send to everyone */
  3231. for (i = 1; i <= NumPlayers; i++) {
  3232. q_ptr = Players[i];
  3233. if (!admin) {
  3234. if (check_ignore(i, Ind)) continue;
  3235. if (q_ptr->ignoring_chat) continue;
  3236. if (!broadcast && (p_ptr->limit_chat || q_ptr->limit_chat) &&
  3237. !inarea(&p_ptr->wpos, &q_ptr->wpos)) continue;
  3238. }
  3239. /* Send message */
  3240. if (broadcast) {
  3241. censor_length = strlen(message + 11);
  3242. msg_format(i, "\375\377r[\377%c%s\377r]\377%c %s", c_n, sender, COLOUR_CHAT, message + 11);
  3243. } else if (!me) {
  3244. censor_length = strlen(message + mycolor);
  3245. msg_format(i, "\375\377%c[%s]\377%c %s", c_n, sender, COLOUR_CHAT, message + mycolor);
  3246. /* msg_format(i, "\375\377%c[%s] %s", Ind ? 'B' : 'y', sender, message); */
  3247. }
  3248. else {
  3249. censor_length = strlen(message + 4);
  3250. msg_format(i, "%s %s", sender, message + 4);
  3251. }
  3252. }
  3253. #endif
  3254. censor_message = FALSE;
  3255. p_ptr->warning_chat = 1;
  3256. handle_punish(Ind, censor_punish);
  3257. exec_lua(0, "chat_handler()");
  3258. }
  3259. /* Console talk is automatically sent by 'Server Admin' which is treated as an admin */
  3260. static void console_talk_aux(char *message)
  3261. {
  3262. int i;
  3263. cptr sender = "Server Admin";
  3264. bool me = FALSE, log = TRUE;
  3265. char c_n = 'y'; /* colours of sender name and of brackets (unused atm) around this name */
  3266. bool broadcast = FALSE;
  3267. #ifdef TOMENET_WORLDS
  3268. char tmessage[MSG_LEN]; /* TEMPORARY! We will not send the name soon */
  3269. #else
  3270. player_type *q_ptr;
  3271. #endif
  3272. /* tBot's stuff */
  3273. /* moved here to allow tbot to see fake pvt messages. -Molt */
  3274. strncpy(last_chat_owner, sender, NAME_LEN);
  3275. strncpy(last_chat_line, message, MSG_LEN);
  3276. /* no big brother */
  3277. if (cfg.log_u && log) s_printf("[%s] %s\n", sender, message);
  3278. /* Special - shutdown command (for compatibility) */
  3279. if (prefix(message, "@!shutdown")) {
  3280. /*world_reboot();*/
  3281. shutdown_server();
  3282. return;
  3283. }
  3284. if (message[0] == '/' ){
  3285. if (!strncmp(message, "/me ", 4)) me = TRUE;
  3286. else if (!strncmp(message, "/broadcast ", 11)) broadcast = TRUE;
  3287. else return;
  3288. }
  3289. for (i = 1; i <= NumPlayers; i++) {
  3290. if (Players[i]->conn == NOT_CONNECTED) continue;
  3291. Players[i]->talk = 0;
  3292. }
  3293. censor_message = TRUE;
  3294. #ifdef TOMENET_WORLDS
  3295. if (broadcast) {
  3296. snprintf(tmessage, sizeof(tmessage), "\375\377r[\377%c%s\377r]\377%c %s", c_n, sender, COLOUR_CHAT, message + 11);
  3297. censor_length = strlen(message + 11);
  3298. } else if (!me) {
  3299. snprintf(tmessage, sizeof(tmessage), "\375\377%c[%s]\377%c %s", c_n, sender, COLOUR_CHAT, message);
  3300. censor_length = strlen(message);
  3301. } else {
  3302. snprintf(tmessage, sizeof(tmessage), "\375\377%c[%s %s]", c_n, sender, message + 4);
  3303. censor_length = strlen(message + 4);
  3304. }
  3305. #else
  3306. /* Send to everyone */
  3307. for (i = 1; i <= NumPlayers; i++) {
  3308. q_ptr = Players[i];
  3309. /* Send message */
  3310. if (broadcast) {
  3311. censor_length = strlen(message + 11);
  3312. msg_format(i, "\375\377r[\377%c%s\377r]\377%c %s", c_n, sender, COLOUR_CHAT, message + 11);
  3313. } else if (!me) {
  3314. censor_length = strlen(message);
  3315. msg_format(i, "\375\377%c[%s]\377%c %s", c_n, sender, COLOUR_CHAT, message);
  3316. }
  3317. else {
  3318. censor_length = strlen(message + 4);
  3319. msg_format(i, "%s %s", sender, message + 4);
  3320. }
  3321. }
  3322. #endif
  3323. censor_message = FALSE;
  3324. exec_lua(0, "chat_handler()");
  3325. }
  3326. /* Check for swear words, censor + punish */
  3327. int handle_censor(char *message) {
  3328. #ifdef CENSOR_SWEARING
  3329. if (censor_swearing) return censor(message);
  3330. #endif
  3331. return 0;
  3332. }
  3333. void handle_punish(int Ind, int level) {
  3334. switch (level) {
  3335. case 0:
  3336. break;
  3337. case 1:
  3338. msg_print(Ind, "Please do not swear.");
  3339. break;
  3340. default:
  3341. imprison(Ind, level * 20, "swearing");
  3342. }
  3343. }
  3344. /* toggle AFK mode off if it's currently on, also reset idle time counter for in-game character.
  3345. required for cloaking mode! - C. Blue */
  3346. void un_afk_idle(int Ind) {
  3347. Players[Ind]->idle_char = 0;
  3348. if (Players[Ind]->afk) toggle_afk(Ind, "");
  3349. stop_cloaking(Ind);
  3350. }
  3351. /*
  3352. * toggle AFK mode on/off. - Jir -
  3353. */
  3354. //#define ALLOW_AFK_COLOURCODES
  3355. #ifdef ALLOW_AFK_COLOURCODES
  3356. void toggle_afk(int Ind, char *msg0)
  3357. #else
  3358. void toggle_afk(int Ind, char *msg)
  3359. #endif
  3360. {
  3361. player_type *p_ptr = Players[Ind];
  3362. char afk[MAX_CHARS];
  3363. int i = 0;
  3364. #ifdef ALLOW_AFK_COLOURCODES
  3365. char msg[MAX_CHARS], *m = msg0;
  3366. /* strip colour codes and cap message at len 60 */
  3367. while ((*m) && i < 60) {
  3368. if (*m == '\377') {
  3369. m++;
  3370. if (*m == '\377') {
  3371. msg[i++] = '{';
  3372. }
  3373. } else msg[i++] = *m;
  3374. m++;
  3375. }
  3376. msg[i] = 0;
  3377. #endif
  3378. /* don't go un-AFK from auto-retaliation */
  3379. if (p_ptr->afk && p_ptr->auto_retaliaty) return;
  3380. /* don't go AFK while shooting-till-kill (target dummy, maybe ironwing ;)) */
  3381. if (!p_ptr->afk && p_ptr->shooting_till_kill) return;
  3382. strcpy(afk, "");
  3383. if (p_ptr->afk && !msg[0]) {
  3384. if (strlen(p_ptr->afk_msg) == 0)
  3385. msg_print(Ind, "AFK mode is turned \377GOFF\377w.");
  3386. else
  3387. msg_format(Ind, "AFK mode is turned \377GOFF\377w. (%s\377w)", p_ptr->afk_msg);
  3388. if (!p_ptr->admin_dm) {
  3389. if (strlen(p_ptr->afk_msg) == 0)
  3390. snprintf(afk, sizeof(afk), "\377%c%s has returned from AFK.", COLOUR_AFK, p_ptr->name);
  3391. else
  3392. snprintf(afk, sizeof(afk), "\377%c%s has returned from AFK. (%s\377%c)", COLOUR_AFK, p_ptr->name, p_ptr->afk_msg, COLOUR_AFK);
  3393. }
  3394. p_ptr->afk = FALSE;
  3395. /* Clear everyone's afk_noticed */
  3396. for (i = 1; i <= NumPlayers; i++)
  3397. player_list_del(&Players[i]->afk_noticed, p_ptr->id);
  3398. } else {
  3399. /* hack: lose health tracker so we actually get to see the 'AFK'
  3400. (for example we might've attacked the target dummy before). */
  3401. health_track(Ind, 0);
  3402. /* stop every major action */
  3403. disturb(Ind, 1, 1); /* ,1) = keep resting! */
  3404. strncpy(p_ptr->afk_msg, msg, MAX_CHARS - 1);
  3405. p_ptr->afk_msg[MAX_CHARS - 1] = '\0';
  3406. if (strlen(p_ptr->afk_msg) == 0)
  3407. msg_print(Ind, "AFK mode is turned \377rON\377w.");
  3408. else
  3409. msg_format(Ind, "AFK mode is turned \377rON\377w. (%s\377w)", p_ptr->afk_msg);
  3410. if (!p_ptr->admin_dm) {
  3411. if (strlen(p_ptr->afk_msg) == 0)
  3412. snprintf(afk, sizeof(afk), "\377%c%s seems to be AFK now.", COLOUR_AFK, p_ptr->name);
  3413. else
  3414. snprintf(afk, sizeof(afk), "\377%c%s seems to be AFK now. (%s\377%c)", COLOUR_AFK, p_ptr->name, p_ptr->afk_msg, COLOUR_AFK);
  3415. }
  3416. p_ptr->afk = TRUE;
  3417. /* actually a hint for newbie rogues couldn't hurt */
  3418. if (p_ptr->tim_blacklist)
  3419. msg_print(Ind, "\376\377yNote: Your blacklist timer won't decrease while AFK.");
  3420. /* still too many starvations, so give a warning - C. Blue */
  3421. if (p_ptr->food < PY_FOOD_ALERT) {
  3422. p_ptr->paging = 6; /* add some beeps, too - mikaelh */
  3423. msg_print(Ind, "\374\377RWARNING: Going AFK while hungry or weak can result in starvation! Eat first!");
  3424. }
  3425. /* Since Mark's mimic died in front of Minas XBM due to this.. - C. Blue */
  3426. if (p_ptr->tim_wraith) {
  3427. p_ptr->paging = 6;
  3428. msg_print(Ind, "\374\377RWARNING: Going AFK in wraithform is very dangerous because wraithform impairs auto-retaliation!");
  3429. }
  3430. }
  3431. /* Replaced msg_broadcast by this, to allow /ignore and /ic */
  3432. /* Tell every player */
  3433. for (i = 1; i <= NumPlayers; i++) {
  3434. /* Skip disconnected players */
  3435. if (Players[i]->conn == NOT_CONNECTED) continue;
  3436. if (check_ignore(i, Ind)) continue;
  3437. if (Players[i]->ignoring_chat && !(p_ptr->party && player_in_party(p_ptr->party, i))) continue;
  3438. /* Skip himself */
  3439. if (i == Ind) continue;
  3440. /* Tell this one */
  3441. msg_print(i, afk);
  3442. }
  3443. p_ptr->redraw |= PR_EXTRA;
  3444. redraw_stuff(Ind);
  3445. return;
  3446. }
  3447. /*
  3448. * A player has sent a message to the rest of the world.
  3449. *
  3450. * Parse it and send to everyone or to only the person(s) he requested.
  3451. *
  3452. * Note that more than one message may get sent at once, seperated by
  3453. * tabs ('\t'). Thus, this function splits them and calls
  3454. * "player_talk_aux" to do the dirty work.
  3455. */
  3456. void player_talk(int Ind, char *message)
  3457. {
  3458. char *cur, *next;
  3459. /* Start at the beginning */
  3460. cur = message;
  3461. /* Process until out of messages */
  3462. while (cur)
  3463. {
  3464. /* Find the next tab */
  3465. next = strchr(cur, '\t');
  3466. /* Stop out the tab */
  3467. if (next)
  3468. {
  3469. /* Replace with \0 */
  3470. *next = '\0';
  3471. }
  3472. /* Process this message */
  3473. player_talk_aux(Ind, cur);
  3474. /* Move to the next one */
  3475. if (next)
  3476. {
  3477. /* One step past the \0 */
  3478. cur = next + 1;
  3479. }
  3480. else
  3481. {
  3482. /* No more message */
  3483. cur = NULL;
  3484. }
  3485. }
  3486. }
  3487. /*
  3488. * Check a char for "vowel-hood"
  3489. */
  3490. bool is_a_vowel(int ch)
  3491. {
  3492. switch (ch)
  3493. {
  3494. case 'a':
  3495. case 'e':
  3496. case 'i':
  3497. case 'o':
  3498. case 'u':
  3499. case 'A':
  3500. case 'E':
  3501. case 'I':
  3502. case 'O':
  3503. case 'U':
  3504. return (TRUE);
  3505. }
  3506. return (FALSE);
  3507. }
  3508. /*
  3509. * Look up a player/party name, allowing abbreviations. - Jir -
  3510. * (looking up party name this way can be rather annoying though)
  3511. *
  3512. * returns 0 if not found/error(, minus value if party.)
  3513. *
  3514. * if 'party' is TRUE, party name is also looked up.
  3515. */
  3516. int name_lookup_loose(int Ind, cptr name, u16b party, bool include_account_names)
  3517. {
  3518. int i, j, len, target = 0;
  3519. player_type *q_ptr, *p_ptr;
  3520. cptr problem = "";
  3521. bool party_online;
  3522. p_ptr=Players[Ind];
  3523. /* don't waste time */
  3524. if(p_ptr==(player_type*)NULL) return(0);
  3525. /* Acquire length of search string */
  3526. len = strlen(name);
  3527. /* Look for a recipient who matches the search string */
  3528. if (len) {
  3529. /* Check players */
  3530. for (i = 1; i <= NumPlayers; i++) {
  3531. /* Check this one */
  3532. q_ptr = Players[i];
  3533. /* Skip if disconnected */
  3534. if (q_ptr->conn == NOT_CONNECTED) continue;
  3535. /* let admins chat */
  3536. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3537. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3538. && strcasecmp(p_ptr->accountname, "kurzel")
  3539. && strcasecmp(p_ptr->accountname, "moltor")
  3540. && strcasecmp(p_ptr->accountname, "the_sandman")
  3541. && strcasecmp(p_ptr->accountname, "faith")
  3542. && strcasecmp(p_ptr->accountname, "mikaelh")
  3543. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3544. /* Check name */
  3545. if (!strncasecmp(q_ptr->name, name, len)) {
  3546. /* Set target if not set already */
  3547. if (!target) {
  3548. target = i;
  3549. } else {
  3550. /* Matching too many people */
  3551. problem = "players";
  3552. }
  3553. /* Check for exact match */
  3554. if (len == (int)strlen(q_ptr->name)) {
  3555. /* Never a problem */
  3556. target = i;
  3557. problem = "";
  3558. /* Finished looking */
  3559. break;
  3560. }
  3561. }
  3562. }
  3563. /* Then check accounts */
  3564. if (include_account_names && !target) for (i = 1; i <= NumPlayers; i++) {
  3565. /* Check this one */
  3566. q_ptr = Players[i];
  3567. /* Skip if disconnected */
  3568. if (q_ptr->conn == NOT_CONNECTED) continue;
  3569. /* let admins chat */
  3570. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3571. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3572. && strcasecmp(p_ptr->accountname, "kurzel")
  3573. && strcasecmp(p_ptr->accountname, "moltor")
  3574. && strcasecmp(p_ptr->accountname, "the_sandman")
  3575. && strcasecmp(p_ptr->accountname, "faith")
  3576. && strcasecmp(p_ptr->accountname, "mikaelh")
  3577. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3578. /* Check name */
  3579. if (!strncasecmp(q_ptr->accountname, name, len)) {
  3580. /* Set target if not set already */
  3581. if (!target) {
  3582. target = i;
  3583. } else {
  3584. /* Matching too many people */
  3585. problem = "players";
  3586. }
  3587. /* Check for exact match */
  3588. if (len == (int)strlen(q_ptr->accountname)) {
  3589. /* Never a problem */
  3590. target = i;
  3591. problem = "";
  3592. /* Finished looking */
  3593. break;
  3594. }
  3595. }
  3596. }
  3597. /* Check parties */
  3598. if (party && !target) {
  3599. for (i = 1; i < MAX_PARTIES; i++) {
  3600. /* Skip if empty */
  3601. if (!parties[i].members) continue;
  3602. /* Check that the party has players online - mikaelh */
  3603. party_online = FALSE;
  3604. for (j = 1; j <= NumPlayers; j++) {
  3605. /* Check this one */
  3606. q_ptr = Players[j];
  3607. /* Skip if disconnected */
  3608. if (q_ptr->conn == NOT_CONNECTED) continue;
  3609. /* Check if the player belongs to this party */
  3610. if (q_ptr->party == i) {
  3611. party_online = TRUE;
  3612. break;
  3613. }
  3614. }
  3615. if (!party_online) continue;
  3616. /* Check name */
  3617. if (!strncasecmp(parties[i].name, name, len)) {
  3618. /* Set target if not set already */
  3619. if (!target) {
  3620. target = 0 - i;
  3621. } else {
  3622. /* Matching too many parties */
  3623. problem = "parties";
  3624. }
  3625. /* Check for exact match */
  3626. if (len == (int)strlen(parties[i].name)) {
  3627. /* Never a problem */
  3628. target = 0 - i;
  3629. problem = "";
  3630. /* Finished looking */
  3631. break;
  3632. }
  3633. }
  3634. }
  3635. }
  3636. }
  3637. /* Check for recipient set but no match found */
  3638. if ((len && !target) || (target < 0 && !party)) {
  3639. /* Send an error message */
  3640. msg_format(Ind, "Could not match name '%s'.", name);
  3641. /* Give up */
  3642. return 0;
  3643. }
  3644. /* Check for multiple recipients found */
  3645. if (strlen(problem)) {
  3646. /* Send an error message */
  3647. msg_format(Ind, "'%s' matches too many %s.", name, problem);
  3648. /* Give up */
  3649. return 0;
  3650. }
  3651. /* Success */
  3652. return target;
  3653. }
  3654. /* same as name_lookup_loose, but without warning message if no name was found */
  3655. int name_lookup_loose_quiet(int Ind, cptr name, u16b party, bool include_account_names)
  3656. {
  3657. int i, j, len, target = 0;
  3658. player_type *q_ptr, *p_ptr;
  3659. cptr problem = "";
  3660. bool party_online;
  3661. p_ptr = Players[Ind];
  3662. /* don't waste time */
  3663. if(p_ptr == (player_type*)NULL) return(0);
  3664. /* Acquire length of search string */
  3665. len = strlen(name);
  3666. /* Look for a recipient who matches the search string */
  3667. if (len) {
  3668. /* Check players */
  3669. for (i = 1; i <= NumPlayers; i++) {
  3670. /* Check this one */
  3671. q_ptr = Players[i];
  3672. /* Skip if disconnected */
  3673. if (q_ptr->conn == NOT_CONNECTED) continue;
  3674. /* let admins chat */
  3675. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3676. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3677. && strcasecmp(p_ptr->accountname, "kurzel")
  3678. && strcasecmp(p_ptr->accountname, "moltor")
  3679. && strcasecmp(p_ptr->accountname, "the_sandman")
  3680. && strcasecmp(p_ptr->accountname, "faith")
  3681. && strcasecmp(p_ptr->accountname, "mikaelh")
  3682. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3683. /* Check name */
  3684. if (!strncasecmp(q_ptr->name, name, len)) {
  3685. /* Set target if not set already */
  3686. if (!target) {
  3687. target = i;
  3688. } else {
  3689. /* Matching too many people */
  3690. problem = "players";
  3691. }
  3692. /* Check for exact match */
  3693. if (len == (int)strlen(q_ptr->name)) {
  3694. /* Never a problem */
  3695. target = i;
  3696. problem = "";
  3697. /* Finished looking */
  3698. break;
  3699. }
  3700. }
  3701. }
  3702. /* Then check accounts */
  3703. if (include_account_names && !target) for (i = 1; i <= NumPlayers; i++) {
  3704. /* Check this one */
  3705. q_ptr = Players[i];
  3706. /* Skip if disconnected */
  3707. if (q_ptr->conn == NOT_CONNECTED) continue;
  3708. /* let admins chat */
  3709. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3710. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3711. && strcasecmp(p_ptr->accountname, "kurzel")
  3712. && strcasecmp(p_ptr->accountname, "moltor")
  3713. && strcasecmp(p_ptr->accountname, "the_sandman")
  3714. && strcasecmp(p_ptr->accountname, "faith")
  3715. && strcasecmp(p_ptr->accountname, "mikaelh")
  3716. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3717. /* Check name */
  3718. if (!strncasecmp(q_ptr->accountname, name, len)) {
  3719. /* Set target if not set already */
  3720. if (!target) {
  3721. target = i;
  3722. } else {
  3723. /* Matching too many people */
  3724. problem = "players";
  3725. }
  3726. /* Check for exact match */
  3727. if (len == (int)strlen(q_ptr->accountname)) {
  3728. /* Never a problem */
  3729. target = i;
  3730. problem = "";
  3731. /* Finished looking */
  3732. break;
  3733. }
  3734. }
  3735. }
  3736. /* Check parties */
  3737. if (party && !target) {
  3738. for (i = 1; i < MAX_PARTIES; i++) {
  3739. /* Skip if empty */
  3740. if (!parties[i].members) continue;
  3741. /* Check that the party has players online - mikaelh */
  3742. party_online = FALSE;
  3743. for (j = 1; j <= NumPlayers; j++) {
  3744. /* Check this one */
  3745. q_ptr = Players[j];
  3746. /* Skip if disconnected */
  3747. if (q_ptr->conn == NOT_CONNECTED) continue;
  3748. /* Check if the player belongs to this party */
  3749. if (q_ptr->party == i) {
  3750. party_online = TRUE;
  3751. break;
  3752. }
  3753. }
  3754. if (!party_online) continue;
  3755. /* Check name */
  3756. if (!strncasecmp(parties[i].name, name, len)) {
  3757. /* Set target if not set already */
  3758. if (!target) {
  3759. target = 0 - i;
  3760. } else {
  3761. /* Matching too many parties */
  3762. problem = "parties";
  3763. }
  3764. /* Check for exact match */
  3765. if (len == (int)strlen(parties[i].name)) {
  3766. /* Never a problem */
  3767. target = 0 - i;
  3768. problem = "";
  3769. /* Finished looking */
  3770. break;
  3771. }
  3772. }
  3773. }
  3774. }
  3775. }
  3776. /* Check for recipient set but no match found */
  3777. if ((len && !target) || (target < 0 && !party)) {
  3778. /* Give up */
  3779. return 0;
  3780. }
  3781. /* Check for multiple recipients found */
  3782. if (strlen(problem)) {
  3783. /* Send an error message */
  3784. msg_format(Ind, "'%s' matches too many %s.", name, problem);
  3785. /* Give up */
  3786. return 0;
  3787. }
  3788. /* Success */
  3789. return target;
  3790. }
  3791. /* copy/pasted from name_lookup_loose(), just without being loose.. */
  3792. int name_lookup(int Ind, cptr name, u16b party, bool include_account_names)
  3793. {
  3794. int i, j, len, target = 0;
  3795. player_type *q_ptr, *p_ptr;
  3796. bool party_online;
  3797. p_ptr = Players[Ind];
  3798. /* don't waste time */
  3799. if (p_ptr == (player_type*)NULL) return(0);
  3800. /* Acquire length of search string */
  3801. len = strlen(name);
  3802. /* Look for a recipient who matches the search string */
  3803. if (len) {
  3804. /* Check players */
  3805. for (i = 1; i <= NumPlayers; i++) {
  3806. /* Check this one */
  3807. q_ptr = Players[i];
  3808. /* Skip if disconnected */
  3809. if (q_ptr->conn == NOT_CONNECTED) continue;
  3810. /* let admins chat */
  3811. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3812. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3813. && strcasecmp(p_ptr->accountname, "kurzel")
  3814. && strcasecmp(p_ptr->accountname, "moltor")
  3815. && strcasecmp(p_ptr->accountname, "the_sandman")
  3816. && strcasecmp(p_ptr->accountname, "faith")
  3817. && strcasecmp(p_ptr->accountname, "mikaelh")
  3818. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3819. /* Check name */
  3820. if (!strcasecmp(q_ptr->name, name)) {
  3821. /* Never a problem */
  3822. target = i;
  3823. /* Finished looking */
  3824. break;
  3825. }
  3826. }
  3827. /* Then check accounts */
  3828. if (include_account_names && !target) for (i = 1; i <= NumPlayers; i++) {
  3829. /* Check this one */
  3830. q_ptr = Players[i];
  3831. /* Skip if disconnected */
  3832. if (q_ptr->conn == NOT_CONNECTED) continue;
  3833. /* let admins chat */
  3834. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3835. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3836. && strcasecmp(p_ptr->accountname, "kurzel")
  3837. && strcasecmp(p_ptr->accountname, "moltor")
  3838. && strcasecmp(p_ptr->accountname, "the_sandman")
  3839. && strcasecmp(p_ptr->accountname, "faith")
  3840. && strcasecmp(p_ptr->accountname, "mikaelh")
  3841. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3842. /* Check name */
  3843. if (!strcasecmp(q_ptr->accountname, name)) {
  3844. /* Never a problem */
  3845. target = i;
  3846. /* Finished looking */
  3847. break;
  3848. }
  3849. }
  3850. /* Check parties */
  3851. if (party && !target) {
  3852. for (i = 1; i < MAX_PARTIES; i++) {
  3853. /* Skip if empty */
  3854. if (!parties[i].members) continue;
  3855. /* Check that the party has players online - mikaelh */
  3856. party_online = FALSE;
  3857. for (j = 1; j <= NumPlayers; j++) {
  3858. /* Check this one */
  3859. q_ptr = Players[j];
  3860. /* Skip if disconnected */
  3861. if (q_ptr->conn == NOT_CONNECTED) continue;
  3862. /* Check if the player belongs to this party */
  3863. if (q_ptr->party == i) {
  3864. party_online = TRUE;
  3865. break;
  3866. }
  3867. }
  3868. if (!party_online) continue;
  3869. /* Check name */
  3870. if (!strcasecmp(parties[i].name, name)) {
  3871. /* Never a problem */
  3872. target = 0 - i;
  3873. /* Finished looking */
  3874. break;
  3875. }
  3876. }
  3877. }
  3878. }
  3879. /* Check for recipient set but no match found */
  3880. if ((len && !target) || (target < 0 && !party)) {
  3881. /* Send an error message */
  3882. msg_format(Ind, "Could not match name '%s'.", name);
  3883. /* Give up */
  3884. return 0;
  3885. }
  3886. /* Success */
  3887. return target;
  3888. }
  3889. /* copy/pasted from name_lookup_loose(), just without being loose.. but with quiet */
  3890. int name_lookup_quiet(int Ind, cptr name, u16b party, bool include_account_names)
  3891. {
  3892. int i, j, len, target = 0;
  3893. player_type *q_ptr, *p_ptr;
  3894. bool party_online;
  3895. p_ptr = Players[Ind];
  3896. /* don't waste time */
  3897. if (p_ptr == (player_type*)NULL) return(0);
  3898. /* Acquire length of search string */
  3899. len = strlen(name);
  3900. /* Look for a recipient who matches the search string */
  3901. if (len) {
  3902. /* Check players */
  3903. for (i = 1; i <= NumPlayers; i++) {
  3904. /* Check this one */
  3905. q_ptr = Players[i];
  3906. /* Skip if disconnected */
  3907. if (q_ptr->conn == NOT_CONNECTED) continue;
  3908. /* let admins chat */
  3909. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3910. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3911. && strcasecmp(p_ptr->accountname, "kurzel")
  3912. && strcasecmp(p_ptr->accountname, "moltor")
  3913. && strcasecmp(p_ptr->accountname, "the_sandman")
  3914. && strcasecmp(p_ptr->accountname, "faith")
  3915. && strcasecmp(p_ptr->accountname, "mikaelh")
  3916. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3917. /* Check name */
  3918. if (!strcasecmp(q_ptr->name, name)) {
  3919. /* Never a problem */
  3920. target = i;
  3921. /* Finished looking */
  3922. break;
  3923. }
  3924. }
  3925. /* Then check accounts */
  3926. if (include_account_names && !target) for (i = 1; i <= NumPlayers; i++) {
  3927. /* Check this one */
  3928. q_ptr = Players[i];
  3929. /* Skip if disconnected */
  3930. if (q_ptr->conn == NOT_CONNECTED) continue;
  3931. /* let admins chat */
  3932. if (q_ptr->admin_dm && !q_ptr->admin_dm_chat && !is_admin(p_ptr)
  3933. /* Hack: allow the following accounts nasty stuff (e.g., spam the DMs!) */
  3934. && strcasecmp(p_ptr->accountname, "kurzel")
  3935. && strcasecmp(p_ptr->accountname, "moltor")
  3936. && strcasecmp(p_ptr->accountname, "the_sandman")
  3937. && strcasecmp(p_ptr->accountname, "faith")
  3938. && strcasecmp(p_ptr->accountname, "mikaelh")
  3939. && strcasecmp(p_ptr->accountname, "c. blue")) continue;
  3940. /* Check name */
  3941. if (!strcasecmp(q_ptr->accountname, name)) {
  3942. /* Never a problem */
  3943. target = i;
  3944. /* Finished looking */
  3945. break;
  3946. }
  3947. }
  3948. /* Check parties */
  3949. if (party && !target) {
  3950. for (i = 1; i < MAX_PARTIES; i++) {
  3951. /* Skip if empty */
  3952. if (!parties[i].members) continue;
  3953. /* Check that the party has players online - mikaelh */
  3954. party_online = FALSE;
  3955. for (j = 1; j <= NumPlayers; j++) {
  3956. /* Check this one */
  3957. q_ptr = Players[j];
  3958. /* Skip if disconnected */
  3959. if (q_ptr->conn == NOT_CONNECTED) continue;
  3960. /* Check if the player belongs to this party */
  3961. if (q_ptr->party == i) {
  3962. party_online = TRUE;
  3963. break;
  3964. }
  3965. }
  3966. if (!party_online) continue;
  3967. /* Check name */
  3968. if (!strcasecmp(parties[i].name, name)) {
  3969. /* Never a problem */
  3970. target = 0 - i;
  3971. /* Finished looking */
  3972. break;
  3973. }
  3974. }
  3975. }
  3976. }
  3977. /* Check for recipient set but no match found */
  3978. if ((len && !target) || (target < 0 && !party)) {
  3979. /* Give up */
  3980. return 0;
  3981. }
  3982. /* Success */
  3983. return target;
  3984. }
  3985. /*
  3986. * Convert bracer '{' into '\377'
  3987. */
  3988. void bracer_ff(char *buf)
  3989. {
  3990. int i, len = strlen(buf);
  3991. for(i=0;i<len;i++){
  3992. if(buf[i]=='{') buf[i]='\377';
  3993. }
  3994. }
  3995. /*
  3996. * make strings from worldpos '-1550ft of (17,15)' - Jir -
  3997. */
  3998. char *wpos_format(int Ind, worldpos *wpos)
  3999. {
  4000. int i = Ind, d = 0, n;
  4001. cptr desc = "";
  4002. bool ville = istown(wpos) && !isdungeontown(wpos);
  4003. dungeon_type *d_ptr = NULL;
  4004. /* Hack for Valinor originally */
  4005. if (i < 0) i = -i;
  4006. if (wpos->wz > 0 && (d_ptr = wild_info[wpos->wy][wpos->wx].tower))
  4007. d = d_ptr->type;
  4008. if (wpos->wz < 0 && (d_ptr = wild_info[wpos->wy][wpos->wx].dungeon))
  4009. d = d_ptr->type;
  4010. if (!wpos->wz && ville)
  4011. for (n = 0; n < numtowns; n++)
  4012. if (town[n].x == wpos->wx && town[n].y == wpos->wy) {
  4013. desc = town_profile[town[n].type].name;
  4014. break;
  4015. }
  4016. if (!strcmp(desc, "")) ville = FALSE;
  4017. if (!i || Players[i]->depth_in_feet) {
  4018. if (Ind >= 0 || (!d && !ville)) {
  4019. return (format("%dft of (%d,%d)", wpos->wz * 50, wpos->wx, wpos->wy));
  4020. } else
  4021. if (!ville)
  4022. return (format("%dft %s", wpos->wz * 50, get_dun_name(wpos->wx, wpos->wy, (wpos->wz > 0), d_ptr, 0)));
  4023. else
  4024. return (format("%s", desc));
  4025. } else {
  4026. if (Ind >= 0 || (!d && !ville)) {
  4027. return (format("Lv %d of (%d,%d)", wpos->wz, wpos->wx, wpos->wy));
  4028. } else
  4029. if (!ville)
  4030. return (format("Lv %d %s", wpos->wz, get_dun_name(wpos->wx, wpos->wy, (wpos->wz > 0), d_ptr, 0)));
  4031. else
  4032. return (format("%s", desc));
  4033. }
  4034. }
  4035. char *wpos_format_compact(int Ind, worldpos *wpos)
  4036. {
  4037. int d = 0, n;
  4038. cptr desc = "";
  4039. bool ville = istown(wpos) && !isdungeontown(wpos);
  4040. dungeon_type *d_ptr;
  4041. if (wpos->wz > 0 && (d_ptr = wild_info[wpos->wy][wpos->wx].tower))
  4042. d = d_ptr->type;
  4043. if (wpos->wz < 0 && (d_ptr = wild_info[wpos->wy][wpos->wx].dungeon))
  4044. d = d_ptr->type;
  4045. if (!wpos->wz && ville)
  4046. for (n = 0; n < numtowns; n++)
  4047. if (town[n].x == wpos->wx && town[n].y == wpos->wy) {
  4048. desc = town_profile[town[n].type].name;
  4049. break;
  4050. }
  4051. if (!strcmp(desc, "")) ville = FALSE;
  4052. if (ville) return (format("%s", desc));
  4053. else {
  4054. if (Players[Ind]->depth_in_feet)
  4055. return (format("%dft (%d,%d)", wpos->wz * 50, wpos->wx, wpos->wy));
  4056. else
  4057. return (format("Lv %d (%d,%d)", wpos->wz, wpos->wx, wpos->wy));
  4058. }
  4059. }
  4060. byte count_bits(u32b array)
  4061. {
  4062. byte k = 0, i;
  4063. if(array)
  4064. for(i = 0; i < 32; i++)
  4065. if(array & (1 << i)) k++;
  4066. return k;
  4067. }
  4068. /*
  4069. * Find a player
  4070. */
  4071. int get_playerind(char *name)
  4072. {
  4073. int i;
  4074. if (name == (char*)NULL) return(-1);
  4075. for(i = 1; i <= NumPlayers; i++) {
  4076. if(Players[i]->conn == NOT_CONNECTED) continue;
  4077. if(!stricmp(Players[i]->name, name)) return(i);
  4078. }
  4079. return(-1);
  4080. }
  4081. int get_playerind_loose(char *name)
  4082. {
  4083. int i, len = strlen(name);
  4084. if (len == 0) return(-1);
  4085. if (name == (char*)NULL) return(-1);
  4086. for(i = 1; i <= NumPlayers; i++) {
  4087. if(Players[i]->conn == NOT_CONNECTED) continue;
  4088. if (!strncasecmp(Players[i]->name, name, len)) return(i);
  4089. }
  4090. return(-1);
  4091. }
  4092. int get_playerslot_loose(int Ind, char *iname) {
  4093. int i, j;
  4094. char o_name[ONAME_LEN], i_name[ONAME_LEN];
  4095. if (iname == (char*)NULL) return(-1);
  4096. if ((*iname) == 0) return(-1);
  4097. for (j = 0; iname[j]; j++) i_name[j] = tolower(iname[j]);
  4098. i_name[j] = 0;
  4099. for (i = 0; i < INVEN_TOTAL; i++) {
  4100. if (!Players[Ind]->inventory[i].k_idx) continue;
  4101. object_desc(0, o_name, &Players[Ind]->inventory[i], FALSE, 3+16+32);
  4102. for (j = 0; o_name[j]; j++) o_name[j] = tolower(o_name[j]);
  4103. if (strstr(o_name, i_name)) return(i);
  4104. }
  4105. return(-1);
  4106. }
  4107. /*
  4108. * Tell the player of the floor feeling. - Jir -
  4109. * NOTE: differs from traditional 'boring' etc feeling!
  4110. * NOTE: added traditional feelings, to warn of dangers - C. Blue
  4111. */
  4112. bool show_floor_feeling(int Ind, bool dungeon_feeling)
  4113. {
  4114. player_type *p_ptr = Players[Ind];
  4115. worldpos *wpos = &p_ptr->wpos;
  4116. struct dungeon_type *d_ptr = getdungeon(wpos);
  4117. dun_level *l_ptr = getfloor(wpos);
  4118. bool felt = FALSE;
  4119. /* Hack for Valinor - C. Blue */
  4120. if (getlevel(wpos) == 200) {
  4121. msg_print(Ind, "\374\377gYou have a wonderful feeling of peace...");
  4122. return TRUE;
  4123. }
  4124. /* XXX devise a better formula */
  4125. if (p_ptr->lev * ((p_ptr->lev >= 40) ? 3 : 2) + 5 < getlevel(wpos)) {
  4126. msg_print(Ind, "\374\377rYou feel an imminent danger!");
  4127. felt = TRUE;
  4128. }
  4129. #ifdef DUNGEON_VISIT_BONUS
  4130. if (dungeon_feeling && d_ptr && dungeon_bonus[d_ptr->id]
  4131. && !(d_ptr->flags3 & DF3_NO_DUNGEON_BONUS)) {
  4132. felt = TRUE;
  4133. switch (dungeon_bonus[d_ptr->id]) {
  4134. case 3: msg_print(Ind, "\377UThis place has not been explored in ages."); break;
  4135. case 2: msg_print(Ind, "\377UThis place has not been explored in a long time."); break;
  4136. case 1: msg_print(Ind, "\377UThis place has not been explored recently."); break;
  4137. }
  4138. }
  4139. #endif
  4140. if (!l_ptr) return(felt);
  4141. #ifdef EXTRA_LEVEL_FEELINGS
  4142. /* Display extra traditional feeling to warn of dangers. - C. Blue
  4143. Note: Only display ONE feeling, thereby setting priorities here.
  4144. Note: Don't display feelings in Training Tower (NO_DEATH). */
  4145. if ((!p_ptr->distinct_floor_feeling && !is_admin(p_ptr)) || (d_ptr->flags2 & DF2_NO_DEATH) ||
  4146. (wpos->wx == WPOS_PVPARENA_X && wpos->wy == WPOS_PVPARENA_Y && wpos->wz == WPOS_PVPARENA_Z)) {
  4147. // msg_print(Ind, "\376\377yLooks like any other level..");
  4148. // msg_print(Ind, "\377ypfft");
  4149. }
  4150. else if (l_ptr->flags2 & LF2_OOD_HI) {
  4151. msg_print(Ind, "\374\377yWhat a terrifying place..");
  4152. felt = TRUE;
  4153. } else if ((l_ptr->flags2 & LF2_VAULT_HI) &&
  4154. (l_ptr->flags2 & LF2_OOD)) {
  4155. msg_print(Ind, "\374\377yWhat a terrifying place..");
  4156. felt = TRUE;
  4157. } else if ((l_ptr->flags2 & LF2_VAULT_OPEN) || // <- TODO: implement :/
  4158. ((l_ptr->flags2 & LF2_VAULT) && (l_ptr->flags2 & LF2_OOD_FREE))) {
  4159. msg_print(Ind, "\374\377yYou sense an air of danger..");
  4160. felt = TRUE;
  4161. } else if (l_ptr->flags2 & LF2_VAULT) {
  4162. msg_print(Ind, "\374\377yFeels somewhat dangerous around here..");
  4163. felt = TRUE;
  4164. } else if (l_ptr->flags2 & LF2_PITNEST_HI) {
  4165. msg_print(Ind, "\374\377yFeels somewhat dangerous around here..");
  4166. felt = TRUE;
  4167. } else if (l_ptr->flags2 & LF2_OOD_FREE) {
  4168. msg_print(Ind, "\374\377yThere's a sensation of challenge..");
  4169. felt = TRUE;
  4170. } /* else if (l_ptr->flags2 & LF2_PITNEST) { //maybe enable, maybe too cheezy
  4171. msg_print(Ind, "\374\377yYou feel your luck is turning..");
  4172. felt = TRUE;
  4173. } */ else if (l_ptr->flags2 & LF2_UNIQUE) {
  4174. msg_print(Ind, "\374\377yThere's a special feeling about this place..");
  4175. felt = TRUE;
  4176. } /* else if (l_ptr->flags2 & LF2_ARTIFACT) { //probably too cheezy, if not then might need combination with threat feelings above
  4177. msg_print(Ind, "\374\377y");
  4178. felt = TRUE;
  4179. } *//* else if (l_ptr->flags2 & LF2_ITEM_OOD) { //probably too cheezy, if not then might need combination with threat feelings above
  4180. msg_print(Ind, "\374\377y");
  4181. felt = TRUE;
  4182. } */ else {
  4183. msg_print(Ind, "\374\377yWhat a boring place..");
  4184. felt = TRUE;
  4185. }
  4186. #endif
  4187. /* Hack^2 -- display the 'feeling' */
  4188. if (l_ptr->flags1 & LF1_NO_MAGIC) {
  4189. msg_print(Ind, "\377oYou feel a suppressive air.");
  4190. /* Automatically dis/re-enable wraith form */
  4191. p_ptr->update |= PU_BONUS;
  4192. }
  4193. if (l_ptr->flags1 & LF1_NO_GENO)
  4194. //sounds as if it's good for the player msg_print(Ind, "\377oYou have a feeling of peace...");
  4195. msg_print(Ind, "\377oThe air seems distorted.");
  4196. if (l_ptr->flags1 & LF1_NO_MAP)
  4197. msg_print(Ind, "\377oYou lose all sense of direction...");
  4198. if (l_ptr->flags1 & LF1_NO_MAGIC_MAP)
  4199. msg_print(Ind, "\377oYou feel like a stranger...");
  4200. if (l_ptr->flags1 & LF1_NO_DESTROY)
  4201. msg_print(Ind, "\377oThe walls here seem very solid.");
  4202. if (l_ptr->flags1 & LF1_NO_GHOST)
  4203. msg_print(Ind, "\377oYou feel that your life hangs in the balance!"); //credits to Moltor actually, ha!:)
  4204. #if 0
  4205. if (l_ptr->flags1 & DF1_NO_RECALL)
  4206. msg_print(Ind, "\377oThere is strong magic enclosing this dungeon.");
  4207. #endif
  4208. /* Can leave IRONMAN? */
  4209. if ((l_ptr->flags1 & LF1_IRON_RECALL || ((d_ptr->flags1 & DF1_FORCE_DOWN) && d_ptr->maxdepth == ABS(p_ptr->wpos.wz)))
  4210. && !(d_ptr->flags2 & DF2_NO_EXIT_WOR))
  4211. msg_print(Ind, "\377gYou don't sense a magic barrier here!");
  4212. return(l_ptr->flags1 & LF1_FEELING_MASK ? TRUE : felt);
  4213. }
  4214. /*
  4215. * Given item name as string, return the index in k_info array. Name
  4216. * must exactly match (look out for commas and the like!), or else 0 is
  4217. * returned. Case doesn't matter. -DG-
  4218. */
  4219. int test_item_name(cptr name)
  4220. {
  4221. int i;
  4222. /* Scan the items */
  4223. for (i = 1; i < max_k_idx; i++)
  4224. {
  4225. object_kind *k_ptr = &k_info[i];
  4226. cptr obj_name = k_name + k_ptr->name;
  4227. /* If name matches, give us the number */
  4228. if (stricmp(name, obj_name) == 0) return (i);
  4229. }
  4230. return (0);
  4231. }
  4232. /*
  4233. * Middle-Earth (Imladris) calendar code from ToME
  4234. */
  4235. /*
  4236. * Break scalar time
  4237. */
  4238. s32b bst(s32b what, s32b t)
  4239. {
  4240. #if 0 /* TIMEREWRITE */
  4241. s32b turns = t + (10 * DAY_START);
  4242. switch (what)
  4243. {
  4244. case MINUTE:
  4245. return ((turns / 10 / MINUTE) % 60);
  4246. case HOUR:
  4247. return ((turns / 10 / HOUR) % 24);
  4248. case DAY:
  4249. return ((turns / 10 / DAY) % 365);
  4250. case YEAR:
  4251. return ((turns / 10 / YEAR));
  4252. default:
  4253. return (0);
  4254. }
  4255. #else
  4256. s32b turns = t;
  4257. if (what == MINUTE)
  4258. return ((turns / MINUTE) % 60);
  4259. else if (what == HOUR)
  4260. return ((turns / HOUR) % 24);
  4261. else if (what == DAY)
  4262. return ((((turns / DAY) + START_DAY) % 365));
  4263. else if (what == YEAR)
  4264. return ((turns / YEAR) + START_YEAR);
  4265. else
  4266. return (0);
  4267. #endif
  4268. }
  4269. cptr get_month_name(int day, bool full, bool compact)
  4270. {
  4271. int i = 8;
  4272. static char buf[40];
  4273. /* Find the period name */
  4274. while ((i > 0) && (day < month_day[i]))
  4275. {
  4276. i--;
  4277. }
  4278. switch (i)
  4279. {
  4280. /* Yestare/Mettare */
  4281. case 0:
  4282. case 8:
  4283. {
  4284. char buf2[20];
  4285. snprintf(buf2, 20, "%s", get_day(day + 1));
  4286. if (full) snprintf(buf, 40, "%s (%s day)", month_name[i], buf2);
  4287. else snprintf(buf, 40, "%s", month_name[i]);
  4288. break;
  4289. }
  4290. /* 'Normal' months + Enderi */
  4291. default:
  4292. {
  4293. char buf2[20];
  4294. char buf3[20];
  4295. snprintf(buf2, 20, "%s", get_day(day + 1 - month_day[i]));
  4296. snprintf(buf3, 20, "%s", get_day(day + 1));
  4297. if (full) snprintf(buf, 40, "%s day of %s (%s day)", buf2, month_name[i], buf3);
  4298. else if (compact) snprintf(buf, 40, "%s day of %s", buf2, month_name[i]);
  4299. else snprintf(buf, 40, "%s %s", buf2, month_name[i]);
  4300. break;
  4301. }
  4302. }
  4303. return (buf);
  4304. }
  4305. cptr get_day(int day)
  4306. {
  4307. static char buf[20];
  4308. cptr p = "th";
  4309. if ((day / 10) == 1) ;
  4310. else if ((day % 10) == 1) p = "st";
  4311. else if ((day % 10) == 2) p = "nd";
  4312. else if ((day % 10) == 3) p = "rd";
  4313. snprintf(buf, 20, "%d%s", day, p);
  4314. return (buf);
  4315. }
  4316. int gold_colour(int amt)
  4317. {
  4318. int i, unit = 1;
  4319. for (i = amt; i > 99 ; i >>= 1, unit++) /* naught */;
  4320. if (unit > SV_GOLD_MAX) unit = SV_GOLD_MAX;
  4321. return (lookup_kind(TV_GOLD, unit));
  4322. }
  4323. /* Catching bad players who hack their client.. nasty! */
  4324. void lua_intrusion(int Ind, char *problem_diz)
  4325. {
  4326. s_printf(format("LUA INTRUSION: %s : %s\n", Players[Ind]->name, problem_diz));
  4327. #if 0 /* 4.4.8 client had a bug, mass-near-killing people. Let's turn this silly stuff off. -C. Blue */
  4328. take_hit(Ind, Players[Ind]->chp - 1, "", 0);
  4329. msg_print(Ind, "\377rThat was close huh?!");
  4330. #else
  4331. if (!strcmp(problem_diz, "bad spell level")) {
  4332. msg_print(Ind, "\376\377RERROR: You need higher skill to cast this spell. However, your book shows");
  4333. msg_print(Ind, "\376\377R that you may cast it because your LUA spell scripts are out of date!");
  4334. msg_print(Ind, "\376\377R Please update your client (or at least the LUA files in lib/scpt).");
  4335. // (and don't use '-u' command-line option)
  4336. } else {
  4337. msg_print(Ind, "\376\377RERROR: Your LUA spell scripts seem to be out of date!");
  4338. msg_print(Ind, "\376\377R Please update your client (or at least the LUA files in lib/scpt).");
  4339. // (and don't use '-u' command-line option)
  4340. }
  4341. #endif
  4342. }
  4343. void bbs_add_line(cptr textline)
  4344. {
  4345. int i, j;
  4346. /* either find an empty bbs entry (store its position in j) */
  4347. for (i = 0; i < BBS_LINES; i++)
  4348. if(!strcmp(bbs_line[i], "")) break;
  4349. j = i;
  4350. /* or scroll up by one line, discarding the first line */
  4351. if (i == BBS_LINES)
  4352. for (j = 0; j < BBS_LINES - 1; j++)
  4353. strcpy(bbs_line[j], bbs_line[j + 1]);
  4354. /* write the line to the bbs */
  4355. strncpy(bbs_line[j], textline, MAX_CHARS_WIDE - 3); /* lines get one leading spaces on outputting, so it's 78-1 // was 77 */
  4356. }
  4357. void bbs_del_line(int entry)
  4358. {
  4359. int j;
  4360. if (entry < 0) return;
  4361. if (entry >= BBS_LINES) return;
  4362. for (j = entry; j < BBS_LINES - 1; j++)
  4363. strcpy(bbs_line[j], bbs_line[j + 1]);
  4364. /* erase last line */
  4365. strcpy(bbs_line[BBS_LINES - 1], "");
  4366. }
  4367. void bbs_erase(void)
  4368. {
  4369. int i;
  4370. for (i = 0; i < BBS_LINES; i++)
  4371. strcpy(bbs_line[i], "");
  4372. }
  4373. void pbbs_add_line(u16b party, cptr textline)
  4374. {
  4375. int i, j;
  4376. /* either find an empty bbs entry (store its position in j) */
  4377. for (i = 0; i < BBS_LINES; i++)
  4378. if(!strcmp(pbbs_line[party][i], "")) break;
  4379. j = i;
  4380. /* or scroll up by one line, discarding the first line */
  4381. if (i == BBS_LINES)
  4382. for (j = 0; j < BBS_LINES - 1; j++)
  4383. strcpy(pbbs_line[party][j], pbbs_line[party][j + 1]);
  4384. /* write the line to the bbs */
  4385. strncpy(pbbs_line[party][j], textline, MAX_CHARS_WIDE - 3);
  4386. }
  4387. void gbbs_add_line(byte guild, cptr textline)
  4388. {
  4389. int i, j;
  4390. /* either find an empty bbs entry (store its position in j) */
  4391. for (i = 0; i < BBS_LINES; i++)
  4392. if(!strcmp(gbbs_line[guild][i], "")) break;
  4393. j = i;
  4394. /* or scroll up by one line, discarding the first line */
  4395. if (i == BBS_LINES)
  4396. for (j = 0; j < BBS_LINES - 1; j++)
  4397. strcpy(gbbs_line[guild][j], gbbs_line[guild][j + 1]);
  4398. /* write the line to the bbs */
  4399. strncpy(gbbs_line[guild][j], textline, MAX_CHARS_WIDE - 3);
  4400. }
  4401. /*
  4402. * Add a player id to a linked list.
  4403. * Doesn't check for duplicates
  4404. * Takes a double pointer to the list
  4405. */
  4406. void player_list_add(player_list_type **list, s32b player)
  4407. {
  4408. player_list_type *pl_ptr;
  4409. MAKE(pl_ptr, player_list_type);
  4410. pl_ptr->id = player;
  4411. pl_ptr->next = *list;
  4412. *list = pl_ptr;
  4413. }
  4414. /*
  4415. * Check if a list contains an id.
  4416. */
  4417. bool player_list_find(player_list_type *list, s32b player)
  4418. {
  4419. player_list_type *pl_ptr;
  4420. pl_ptr = list;
  4421. while (pl_ptr)
  4422. {
  4423. if (pl_ptr->id == player)
  4424. {
  4425. return TRUE;
  4426. }
  4427. pl_ptr = pl_ptr->next;
  4428. }
  4429. return FALSE;
  4430. }
  4431. /*
  4432. * Delete an id from a list.
  4433. * Takes a double pointer to the list
  4434. */
  4435. bool player_list_del(player_list_type **list, s32b player)
  4436. {
  4437. player_list_type *pl_ptr, *prev;
  4438. if (*list == NULL) return FALSE;
  4439. /* Check the first node */
  4440. if ((*list)->id == player)
  4441. {
  4442. *list = (*list)->next;
  4443. return TRUE;
  4444. }
  4445. pl_ptr = (*list)->next;
  4446. prev = *list;
  4447. /* Check the rest of the nodes */
  4448. while (pl_ptr)
  4449. {
  4450. if (pl_ptr->id == player)
  4451. {
  4452. prev->next = pl_ptr->next;
  4453. FREE(pl_ptr, player_list_type);
  4454. return TRUE;
  4455. }
  4456. prev = pl_ptr;
  4457. pl_ptr = pl_ptr->next;
  4458. }
  4459. return FALSE;
  4460. }
  4461. /*
  4462. * Free an entire list.
  4463. */
  4464. void player_list_free(player_list_type *list)
  4465. {
  4466. player_list_type *pl_ptr, *tmp;
  4467. pl_ptr = list;
  4468. while (pl_ptr)
  4469. {
  4470. tmp = pl_ptr;
  4471. pl_ptr = pl_ptr->next;
  4472. FREE(tmp, player_list_type);
  4473. }
  4474. }
  4475. /*
  4476. * Check if the client version fills the requirements.
  4477. *
  4478. * Branch has to be an exact match.
  4479. */
  4480. bool is_newer_than(version_type *version, int major, int minor, int patch, int extra, int branch, int build)
  4481. {
  4482. if (version->major < major)
  4483. return FALSE; /* very old */
  4484. else if (version->major > major)
  4485. return TRUE; /* very new */
  4486. else if (version->minor < minor)
  4487. return FALSE; /* pretty old */
  4488. else if (version->minor > minor)
  4489. return TRUE; /* pretty new */
  4490. else if (version->patch < patch)
  4491. return FALSE; /* somewhat old */
  4492. else if (version->patch > patch)
  4493. return TRUE; /* somewhat new */
  4494. else if (version->extra < extra)
  4495. return FALSE; /* a little older */
  4496. else if (version->extra > extra)
  4497. return TRUE; /* a little newer */
  4498. /* Check that the branch is an exact match */
  4499. else if (version->branch == branch)
  4500. {
  4501. /* Now check the build */
  4502. if (version->build < build)
  4503. return FALSE;
  4504. else if (version->build > build)
  4505. return TRUE;
  4506. }
  4507. /* Default */
  4508. return FALSE;
  4509. }
  4510. bool is_older_than(version_type *version, int major, int minor, int patch, int extra, int branch, int build)
  4511. {
  4512. if (version->major > major)
  4513. return FALSE; /* very new */
  4514. else if (version->major < major)
  4515. return TRUE; /* very old */
  4516. else if (version->minor > minor)
  4517. return FALSE; /* pretty new */
  4518. else if (version->minor < minor)
  4519. return TRUE; /* pretty old */
  4520. else if (version->patch > patch)
  4521. return FALSE; /* somewhat new */
  4522. else if (version->patch < patch)
  4523. return TRUE; /* somewhat old */
  4524. else if (version->extra > extra)
  4525. return FALSE; /* a little newer */
  4526. else if (version->extra < extra)
  4527. return TRUE; /* a little older */
  4528. /* Check that the branch is an exact match */
  4529. else if (version->branch == branch)
  4530. {
  4531. /* Now check the build */
  4532. if (version->build > build)
  4533. return FALSE;
  4534. else if (version->build < build)
  4535. return TRUE;
  4536. }
  4537. /* Default */
  4538. return FALSE;
  4539. }
  4540. bool is_same_as(version_type *version, int major, int minor, int patch, int extra, int branch, int build)
  4541. {
  4542. if (version->major == major
  4543. && version->minor == minor
  4544. && version->patch == patch
  4545. && version->extra == extra
  4546. && version->branch == branch
  4547. && version->build == build)
  4548. return TRUE;
  4549. return FALSE;
  4550. }
  4551. /*
  4552. * Since only GNU libc has memfrob, we use our own.
  4553. */
  4554. void my_memfrob(void *s, int n)
  4555. {
  4556. int i;
  4557. char *str;
  4558. str = (char*) s;
  4559. for (i = 0; i < n; i++)
  4560. {
  4561. /* XOR every byte with 42 */
  4562. str[i] ^= 42;
  4563. }
  4564. }
  4565. /* compare player mode compatibility - C. Blue
  4566. Note: returns NULL if compatible.
  4567. strict: Ignore IRONDEEPDIVE_ALLOW_INCOMPAT. */
  4568. cptr compat_pmode(int Ind1, int Ind2, bool strict) {
  4569. #ifdef IRONDEEPDIVE_ALLOW_INCOMPAT
  4570. /* EXPERIMENTAL */
  4571. player_type *p1_ptr = Players[Ind1], *p2_ptr = Players[Ind2];
  4572. if (!strict &&
  4573. in_irondeepdive(&p1_ptr->wpos) &&
  4574. in_irondeepdive(&p2_ptr->wpos))
  4575. return NULL;
  4576. #endif
  4577. if (Players[Ind1]->mode & MODE_PVP) {
  4578. if (!(Players[Ind2]->mode & MODE_PVP)) {
  4579. return "non-pvp";
  4580. }
  4581. } else if (Players[Ind1]->mode & MODE_EVERLASTING) {
  4582. if (!(Players[Ind2]->mode & MODE_EVERLASTING)) {
  4583. return "non-everlasting";
  4584. }
  4585. } else if (Players[Ind2]->mode & MODE_PVP) {
  4586. return "pvp";
  4587. } else if (Players[Ind2]->mode & MODE_EVERLASTING) {
  4588. return "everlasting";
  4589. }
  4590. return NULL; /* means "is compatible" */
  4591. }
  4592. /* compare object and player mode compatibility - C. Blue
  4593. Note: returns NULL if compatible. */
  4594. cptr compat_pomode(int Ind, object_type *o_ptr) {
  4595. #ifdef IRONDEEPDIVE_ALLOW_INCOMPAT
  4596. /* EXPERIMENTAL */
  4597. player_type *p_ptr = Players[Ind];
  4598. if (in_irondeepdive(&p_ptr->wpos) &&
  4599. in_irondeepdive(&o_ptr->wpos))
  4600. return NULL;
  4601. #endif
  4602. if (!o_ptr->owner || is_admin(Players[Ind])) return NULL; /* always compatible */
  4603. if (Players[Ind]->mode & MODE_PVP) {
  4604. if (!(o_ptr->mode & MODE_PVP)) {
  4605. if (o_ptr->mode & MODE_EVERLASTING) {
  4606. if (!(cfg.charmode_trading_restrictions & 2)) {
  4607. return "non-pvp";
  4608. }
  4609. } else if (!(cfg.charmode_trading_restrictions & 4)) {
  4610. return "non-pvp";
  4611. }
  4612. }
  4613. } else if (Players[Ind]->mode & MODE_EVERLASTING) {
  4614. if (o_ptr->mode & MODE_PVP) {
  4615. return "pvp";
  4616. } else if (!(o_ptr->mode & MODE_EVERLASTING)) {
  4617. if (!(cfg.charmode_trading_restrictions & 1)) return "non-everlasting";
  4618. }
  4619. } else if (o_ptr->mode & MODE_PVP) {
  4620. return "pvp";
  4621. } else if (o_ptr->mode & MODE_EVERLASTING) {
  4622. return "everlasting";
  4623. }
  4624. return NULL; /* means "is compatible" */
  4625. }
  4626. /* compare two objects' mode compatibility for stacking/absorbing - C. Blue
  4627. Note: returns NULL if compatible. */
  4628. cptr compat_omode(object_type *o1_ptr, object_type *o2_ptr) {
  4629. #ifdef IRONDEEPDIVE_ALLOW_INCOMPAT
  4630. /* EXPERIMENTAL */
  4631. if ((in_irondeepdive(&o1_ptr->wpos)) &&
  4632. in_irondeepdive(&o2_ptr->wpos))
  4633. return NULL;
  4634. #endif
  4635. /* ownership given for both items? */
  4636. if (!o1_ptr->owner) {
  4637. if (!o2_ptr->owner) return NULL; /* always compatible */
  4638. else return "owned";
  4639. } else if (!o2_ptr->owner) return "owned";
  4640. /* both are owned. so compare actual modes */
  4641. if (o1_ptr->mode & MODE_PVP) {
  4642. if (!(o2_ptr->mode & MODE_PVP)) {
  4643. return "non-pvp";
  4644. }
  4645. } else if (o1_ptr->mode & MODE_EVERLASTING) {
  4646. if (!(o2_ptr->mode & MODE_EVERLASTING)) {
  4647. return "non-everlasting";
  4648. }
  4649. } else if (o2_ptr->mode & MODE_PVP) {
  4650. return "pvp";
  4651. } else if (o2_ptr->mode & MODE_EVERLASTING) {
  4652. return "everlasting";
  4653. }
  4654. return NULL; /* means "is compatible" */
  4655. }
  4656. cptr compat_mode(byte mode1, byte mode2) {
  4657. if (mode1 & MODE_PVP) {
  4658. if (!(mode2 & MODE_PVP)) {
  4659. return "non-pvp";
  4660. }
  4661. } else if (mode1 & MODE_EVERLASTING) {
  4662. if (!(mode2 & MODE_EVERLASTING)) {
  4663. return "non-everlasting";
  4664. }
  4665. } else if (mode2 & MODE_PVP) {
  4666. return "pvp";
  4667. } else if (mode2 & MODE_EVERLASTING) {
  4668. return "everlasting";
  4669. }
  4670. return NULL; /* means "is compatible" */
  4671. }
  4672. /* cut out pseudo-id inscriptions from a string (a note ie inscription usually),
  4673. save resulting string in s2,
  4674. save highest found pseudo-id string in psid. - C. Blue */
  4675. void note_crop_pseudoid(char *s2, char *psid, cptr s) {
  4676. char *p, s0[80];
  4677. int id = 0; /* assume no pseudo-id inscription */
  4678. if (s == NULL) return;
  4679. strcpy(s2, s);
  4680. while (TRUE) {
  4681. strcpy(s0, s2);
  4682. strcpy(s2, "");
  4683. if ((p = strstr(s0, "terrible-"))) {
  4684. strncpy(s2, s0, p - s0);
  4685. s2[p - s0] = '\0';
  4686. strcat(s2, p + 9);
  4687. if (id < 1) id = 1;
  4688. } else if ((p = strstr(s0, "terrible"))) {
  4689. strncpy(s2, s0, p - s0);
  4690. s2[p - s0] = '\0';
  4691. strcat(s2, p + 8);
  4692. if (id < 1) id = 1;
  4693. } else if ((p = strstr(s0, "cursed-"))) {
  4694. strncpy(s2, s0, p - s0);
  4695. s2[p - s0] = '\0';
  4696. strcat(s2, p + 7);
  4697. if (id < 2) id = 2;
  4698. } else if ((p = strstr(s0, "cursed"))) {
  4699. strncpy(s2, s0, p - s0);
  4700. s2[p - s0] = '\0';
  4701. strcat(s2, p + 6);
  4702. if (id < 2) id = 2;
  4703. } else if ((p = strstr(s0, "worthless-"))) {
  4704. strncpy(s2, s0, p - s0);
  4705. s2[p - s0] = '\0';
  4706. strcat(s2, p + 10);
  4707. if (id < 4) id = 4;
  4708. } else if ((p = strstr(s0, "worthless"))) {
  4709. strncpy(s2, s0, p - s0);
  4710. s2[p - s0] = '\0';
  4711. strcat(s2, p + 9);
  4712. if (id < 4) id = 4;
  4713. } else if ((p = strstr(s0, "broken-"))) {
  4714. strncpy(s2, s0, p - s0);
  4715. s2[p - s0] = '\0';
  4716. strcat(s2, p + 7);
  4717. if (id < 5) id = 5;
  4718. } else if ((p = strstr(s0, "broken"))) {
  4719. strncpy(s2, s0, p - s0);
  4720. s2[p - s0] = '\0';
  4721. strcat(s2, p + 6);
  4722. if (id < 5) id = 5;
  4723. } else if ((p = strstr(s0, "average-"))) {
  4724. strncpy(s2, s0, p - s0);
  4725. s2[p - s0] = '\0';
  4726. strcat(s2, p + 8);
  4727. if (id < 6) id = 6;
  4728. } else if ((p = strstr(s0, "average"))) {
  4729. strncpy(s2, s0, p - s0);
  4730. s2[p - s0] = '\0';
  4731. strcat(s2, p + 7);
  4732. if (id < 6) id = 6;
  4733. } else if ((p = strstr(s0, "good-"))) {
  4734. strncpy(s2, s0, p - s0);
  4735. s2[p - s0] = '\0';
  4736. strcat(s2, p + 5);
  4737. if (id < 7) id = 7;
  4738. } else if ((p = strstr(s0, "good"))) {
  4739. strncpy(s2, s0, p - s0);
  4740. s2[p - s0] = '\0';
  4741. strcat(s2, p + 4);
  4742. if (id < 7) id = 7;
  4743. } else if ((p = strstr(s0, "excellent-"))) {
  4744. strncpy(s2, s0, p - s0);
  4745. s2[p - s0] = '\0';
  4746. strcat(s2, p + 10);
  4747. if (id < 8) id = 8;
  4748. } else if ((p = strstr(s0, "excellent"))) {
  4749. strncpy(s2, s0, p - s0);
  4750. s2[p - s0] = '\0';
  4751. strcat(s2, p + 9);
  4752. if (id < 8) id = 8;
  4753. } else if ((p = strstr(s0, "special-"))) {
  4754. strncpy(s2, s0, p - s0);
  4755. s2[p - s0] = '\0';
  4756. strcat(s2, p + 8);
  4757. if (id < 9) id = 9;
  4758. } else if ((p = strstr(s0, "special"))) {
  4759. strncpy(s2, s0, p - s0);
  4760. s2[p - s0] = '\0';
  4761. strcat(s2, p + 7);
  4762. if (id < 9) id = 9;
  4763. } else {
  4764. /* no further replacements to make */
  4765. break;
  4766. }
  4767. }
  4768. strcpy(s2, s0);
  4769. switch (id) {
  4770. case 1: strcpy(psid, "terrible"); break;
  4771. case 2: strcpy(psid, "cursed"); break;
  4772. case 3: strcpy(psid, "bad"); break;
  4773. case 4: strcpy(psid, "worthless"); break;
  4774. case 5: strcpy(psid, "broken"); break;
  4775. case 6: strcpy(psid, "average"); break;
  4776. case 7: strcpy(psid, "good"); break;
  4777. case 8: strcpy(psid, "excellent"); break;
  4778. case 9: strcpy(psid, "special"); break;
  4779. default:
  4780. strcpy(psid, "");
  4781. }
  4782. }
  4783. /* Convert certain characters into HTML entities
  4784. * These characters are <, >, & and "
  4785. * NOTE: The returned string is dynamically allocated
  4786. */
  4787. char *html_escape(const char *str) {
  4788. int i, new_len = 0;
  4789. const char *tmp;
  4790. char *result;
  4791. if (!str) {
  4792. /* Return an empty string */
  4793. result = malloc(1);
  4794. *result = '\0';
  4795. return result;
  4796. }
  4797. /* Calculate the resulting length */
  4798. tmp = str;
  4799. while (*tmp) {
  4800. switch (*tmp) {
  4801. case '<': case '>':
  4802. new_len += 3;
  4803. break;
  4804. case '&':
  4805. new_len += 4;
  4806. break;
  4807. case '"':
  4808. new_len += 5;
  4809. break;
  4810. }
  4811. new_len++;
  4812. tmp++;
  4813. }
  4814. result = malloc(new_len + 1);
  4815. i = 0;
  4816. tmp = str;
  4817. while (*tmp) {
  4818. switch (*tmp) {
  4819. case '<':
  4820. result[i++] = '&';
  4821. result[i++] = 'l';
  4822. result[i++] = 't';
  4823. result[i++] = ';';
  4824. break;
  4825. case '>':
  4826. result[i++] = '&';
  4827. result[i++] = 'g';
  4828. result[i++] = 't';
  4829. result[i++] = ';';
  4830. break;
  4831. case '&':
  4832. result[i++] = '&';
  4833. result[i++] = 'a';
  4834. result[i++] = 'm';
  4835. result[i++] = 'p';
  4836. result[i++] = ';';
  4837. break;
  4838. case '"':
  4839. result[i++] = '&';
  4840. result[i++] = 'q';
  4841. result[i++] = 'u';
  4842. result[i++] = 'o';
  4843. result[i++] = 't';
  4844. result[i++] = ';';
  4845. break;
  4846. default:
  4847. result[i++] = *tmp;
  4848. }
  4849. tmp++;
  4850. }
  4851. /* Terminate */
  4852. result[new_len] = '\0';
  4853. return result;
  4854. }
  4855. /* level generation benchmark */
  4856. void do_benchmark(int Ind) {
  4857. int i, n = 100;
  4858. player_type *p_ptr = Players[Ind];
  4859. struct timeval begin, end;
  4860. int sec, usec;
  4861. #ifndef WINDOWS
  4862. block_timer();
  4863. #endif
  4864. /* Use gettimeofday to get precise time */
  4865. gettimeofday(&begin, NULL);
  4866. for (i = 0; i < n; i++) {
  4867. generate_cave(&p_ptr->wpos, p_ptr);
  4868. }
  4869. gettimeofday(&end, NULL);
  4870. #ifndef WINDOWS
  4871. allow_timer();
  4872. #endif
  4873. /* Calculate the time */
  4874. sec = end.tv_sec - begin.tv_sec;
  4875. usec = end.tv_usec - begin.tv_usec;
  4876. if (usec < 0) {
  4877. usec += 1000000;
  4878. sec--;
  4879. }
  4880. /* Print the result */
  4881. msg_format(Ind, "Generated %d levels in %d.%06d seconds.", n, sec, usec);
  4882. /* Log it too */
  4883. s_printf("BENCHMARK: Generated %d levels in %d.%06d seconds.\n", n, sec, usec);
  4884. }
  4885. /*
  4886. * Get the difference between two timevals as a string.
  4887. */
  4888. cptr timediff(struct timeval *begin, struct timeval *end) {
  4889. static char buf[20];
  4890. int sec, msec, usec;
  4891. sec = end->tv_sec - begin->tv_sec;
  4892. usec = end->tv_usec - begin->tv_usec;
  4893. if (usec < 0) {
  4894. usec += 1000000;
  4895. sec--;
  4896. }
  4897. msec = usec / 1000;
  4898. snprintf(buf, 20, "%d.%03d", sec, msec);
  4899. return buf;
  4900. }
  4901. /* Strip special chars off player input 's', to prevent any problems/colours */
  4902. void strip_control_codes(char *ss, char *s) {
  4903. char *sp = s, *ssp = ss;
  4904. bool skip = FALSE;
  4905. while(TRUE) {
  4906. if (*sp == '\0') { /* end of string has top priority */
  4907. *ssp = '\0';
  4908. break;
  4909. } else if (skip) skip = FALSE; /* a 'code parameter', needs to be stripped too */
  4910. else if ((*sp >= 32) && (*sp <= 127)) { /* normal characters */
  4911. *ssp = *sp;
  4912. ssp++;
  4913. } else if (*sp == '\377') {
  4914. if (*(sp + 1) == '\377') { /* make two '{' become one real '{' */
  4915. *ssp = '{';
  4916. ssp++;
  4917. }
  4918. skip = TRUE; /* strip colour codes */
  4919. }
  4920. sp++;
  4921. }
  4922. }
  4923. /* return a string displaying the flag state - C. Blue */
  4924. cptr flags_str(u32b flags) {
  4925. #if 0 /* disfunctional atm */
  4926. char *fsp = malloc(40 * sizeof(char));
  4927. int b;
  4928. for (b = 0; b < 32; b++) {
  4929. *fsp++ = (flags & (1 << b)) ? '1' : '0';
  4930. if (b % 4 == 3) *fsp++ = ' ';
  4931. }
  4932. *fsp++ = '\0';
  4933. return (fsp - 40);
  4934. #else
  4935. return (NULL);
  4936. #endif
  4937. }
  4938. /* get player's racial attribute */
  4939. cptr get_prace(player_type *p_ptr) {
  4940. #ifdef ENABLE_MAIA
  4941. if (p_ptr->prace == RACE_MAIA && p_ptr->ptrait) {
  4942. if (p_ptr->ptrait == TRAIT_ENLIGHTENED)
  4943. return "Enlightened";
  4944. else if (p_ptr->ptrait == TRAIT_CORRUPTED)
  4945. return "Corrupted";
  4946. else
  4947. return special_prace_lookup[p_ptr->prace];
  4948. } else
  4949. #endif
  4950. return special_prace_lookup[p_ptr->prace];
  4951. }
  4952. /* get player's title */
  4953. cptr get_ptitle(player_type *p_ptr, bool short_form) {
  4954. if (p_ptr->lev < 60) return player_title[p_ptr->pclass][((p_ptr->lev / 5) < 10)? (p_ptr->lev / 5) : 10][(short_form ? 3 : 1) - p_ptr->male];
  4955. return player_title_special[p_ptr->pclass][(p_ptr->lev < PY_MAX_PLAYER_LEVEL) ? (p_ptr->lev - 60) / 10 : 4][(short_form ? 3 : 1) - p_ptr->male];
  4956. }
  4957. #ifdef DUNGEON_VISIT_BONUS
  4958. void reindex_dungeons() {
  4959. # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
  4960. int i;
  4961. # endif
  4962. int x, y;
  4963. wilderness_type *w_ptr;
  4964. struct dungeon_type *d_ptr;
  4965. dungeon_id_max = 0;
  4966. for (y = 0; y < MAX_WILD_Y; y++) {
  4967. for (x = 0; x < MAX_WILD_X; x++) {
  4968. w_ptr = &wild_info[y][x];
  4969. if (w_ptr->flags & WILD_F_UP) {
  4970. d_ptr = w_ptr->tower;
  4971. d_ptr->id = ++dungeon_id_max;
  4972. dungeon_visit_frequency[dungeon_id_max] = 0;
  4973. dungeon_x[dungeon_id_max] = x;
  4974. dungeon_y[dungeon_id_max] = y;
  4975. dungeon_tower[dungeon_id_max] = TRUE;
  4976. /* Initialize all dungeons at 'low rest bonus' */
  4977. set_dungeon_bonus(dungeon_id_max, TRUE);
  4978. s_printf(" indexed tower at %d,%d: id = %d\n", x, y, dungeon_id_max);
  4979. }
  4980. if (w_ptr->flags & WILD_F_DOWN) {
  4981. d_ptr = w_ptr->dungeon;
  4982. d_ptr->id = ++dungeon_id_max;
  4983. dungeon_visit_frequency[dungeon_id_max] = 0;
  4984. dungeon_x[dungeon_id_max] = x;
  4985. dungeon_y[dungeon_id_max] = y;
  4986. dungeon_tower[dungeon_id_max] = FALSE;
  4987. /* Initialize all dungeons at 'low rest bonus' */
  4988. set_dungeon_bonus(dungeon_id_max, TRUE);
  4989. s_printf(" indexed dungeon at %d,%d: id = %d\n", x, y, dungeon_id_max);
  4990. }
  4991. }
  4992. }
  4993. # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
  4994. for (i = 0; i < 20; i++)
  4995. depthrange_visited[i] = 0;
  4996. # endif
  4997. s_printf("Reindexed %d dungeons/towers.\n", dungeon_id_max);
  4998. }
  4999. void set_dungeon_bonus(int id, bool reset) {
  5000. if (reset) {
  5001. /* Initialize dungeon at 'low rest bonus' */
  5002. dungeon_visit_frequency[id] = ((VISIT_TIME_CAP * 17) / 20) - 1; /* somewhat below the threshold */
  5003. dungeon_bonus[id] = 1;
  5004. return;
  5005. }
  5006. if (dungeon_visit_frequency[id] < VISIT_TIME_CAP / 10)
  5007. dungeon_bonus[id] = 3;
  5008. else if (dungeon_visit_frequency[id] < VISIT_TIME_CAP / 2)
  5009. dungeon_bonus[id] = 2;
  5010. else if (dungeon_visit_frequency[id] < (VISIT_TIME_CAP * 19) / 20)
  5011. dungeon_bonus[id] = 1;
  5012. else
  5013. dungeon_bonus[id] = 0;
  5014. }
  5015. #endif
  5016. /*
  5017. * Shuffle an array of integers using the Fisher-Yates algorithm.
  5018. */
  5019. void intshuffle(int *array, int size) {
  5020. int i, j, tmp;
  5021. for (i = size - 1; i > 0; i--) {
  5022. j = rand_int(i + 1);
  5023. tmp = array[i];
  5024. array[i] = array[j];
  5025. array[j] = tmp;
  5026. }
  5027. }
  5028. /* for all the dungeons/towers that are special, yet use the type 0 dungeon template - C. Blue
  5029. todo: actually create own types for these. would also make DF3_JAIL_DUNGEON obsolete. */
  5030. char *get_dun_name(int x, int y, bool tower, dungeon_type *d_ptr, int type) {
  5031. static char *jail = "Jail Dungeon";
  5032. static char *pvp_arena = "PvP Arena";
  5033. static char *highlander = "Highlands";
  5034. static char *irondeepdive = "Ironman Deep Dive Challenge";
  5035. if (d_ptr) type = d_ptr->type;
  5036. /* normal dungeon */
  5037. if (type) return (d_name + d_info[type].name);
  5038. /* special type 0 (yet) dungeons */
  5039. if (x == WPOS_PVPARENA_X &&
  5040. y == WPOS_PVPARENA_Y &&
  5041. tower == (WPOS_PVPARENA_Z > 0))
  5042. return pvp_arena;
  5043. if (x == WPOS_HIGHLANDER_DUN_X &&
  5044. y == WPOS_HIGHLANDER_DUN_Y &&
  5045. tower == (WPOS_HIGHLANDER_DUN_Z > 0))
  5046. return highlander;
  5047. if (x == WPOS_IRONDEEPDIVE_X &&
  5048. y == WPOS_IRONDEEPDIVE_Y &&
  5049. tower == (WPOS_IRONDEEPDIVE_Z > 0))
  5050. return irondeepdive;
  5051. if (d_ptr && (
  5052. #if 0 /* obsolete fortunately (/fixjaildun) */
  5053. /* ughhh */
  5054. (d_ptr->baselevel == 30 && d_ptr->maxdepth == 30 &&
  5055. (d_ptr->flags1 & DF1_FORGET) &&
  5056. (d_ptr->flags2 & DF2_IRON))
  5057. ||
  5058. #endif
  5059. /* yay */
  5060. (d_ptr->flags3 & DF3_JAIL_DUNGEON) ))
  5061. return jail;
  5062. /* really just "Wilderness" */
  5063. return (d_name + d_info[type].name);
  5064. }
  5065. /* Add gold to the player's gold, for easier handling. - C. Blue
  5066. Returns FALSE if we already own 2E9 Au. */
  5067. bool gain_au(int Ind, u32b amt, bool quiet, bool exempt) {
  5068. player_type *p_ptr = Players[Ind];
  5069. /* hack: prevent s32b overflow */
  5070. if (2000000000 - amt < p_ptr->au) {
  5071. if (!quiet) msg_format(Ind, "\377yYou cannot carry more than 2 billion worth of gold!");
  5072. return FALSE;
  5073. } else {
  5074. #ifdef EVENT_TOWNIE_GOLD_LIMIT
  5075. if ((p_ptr->mode & MODE_DED_IDDC) && !in_irondeepdive(&p_ptr->wpos)
  5076. && p_ptr->gold_picked_up == EVENT_TOWNIE_GOLD_LIMIT) {
  5077. msg_print(Ind, "\377yYou cannot collect any more cash or your life would be forfeit.");
  5078. return FALSE;
  5079. }
  5080. #endif
  5081. /* Collect the gold */
  5082. p_ptr->au += amt;
  5083. p_ptr->redraw |= (PR_GOLD);
  5084. }
  5085. if (exempt) return TRUE;
  5086. #ifdef EVENT_TOWNIE_GOLD_LIMIT
  5087. /* if EVENT_TOWNIE_GOLD_LIMIT is 0 then nothing happens */
  5088. if (p_ptr->gold_picked_up <= EVENT_TOWNIE_GOLD_LIMIT) {
  5089. p_ptr->gold_picked_up += (amt > EVENT_TOWNIE_GOLD_LIMIT) ? EVENT_TOWNIE_GOLD_LIMIT : amt;
  5090. if (p_ptr->gold_picked_up > EVENT_TOWNIE_GOLD_LIMIT
  5091. && !p_ptr->max_exp) {
  5092. msg_print(Ind, "You gain a tiny bit of experience from collecting cash.");
  5093. gain_exp(Ind, 1);
  5094. }
  5095. }
  5096. #endif
  5097. return TRUE;
  5098. }
  5099. /* backup all house prices and contents for all players to lib/save/estate/ */
  5100. #define ESTATE_BACKUP_VERSION "v1"
  5101. bool backup_estate(void) {
  5102. FILE *fp;
  5103. char buf[MAX_PATH_LENGTH], buf2[MAX_PATH_LENGTH], savefile[NAME_LEN], c;
  5104. cptr name;
  5105. int i, j, k;
  5106. int sy, sx, ey,ex , x, y;
  5107. cave_type **zcave, *c_ptr;
  5108. bool newly_created, allocated;
  5109. u32b au;
  5110. house_type *h_ptr;
  5111. struct dna_type *dna;
  5112. struct worldpos *wpos;
  5113. object_type *o_ptr;
  5114. s_printf("Backing up all real estate...\n");
  5115. /* create folder lib/save/estate if not existing */
  5116. path_build(buf2, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "estate");
  5117. /* scan all houses */
  5118. for (i = 0; i < num_houses; i++) {
  5119. h_ptr = &houses[i];
  5120. if (!h_ptr->dna->owner) continue;
  5121. wpos = &h_ptr->wpos;
  5122. dna = h_ptr->dna;
  5123. /* assume worst possible charisma (3) */
  5124. au = dna->price / 100 * adj_chr_gold[0];
  5125. if (au < 100) au = 100;
  5126. //h_ptr->dy,dx
  5127. /* WARNING: For now unable to save guild halls */
  5128. if (h_ptr->dna->owner_type != OT_PLAYER) continue;
  5129. name = lookup_player_name(h_ptr->dna->owner);
  5130. if (!name) {
  5131. s_printf(" warning: house %d's owner %d doesn't have a name.\n", i, h_ptr->dna->owner);
  5132. continue;
  5133. }
  5134. /* create backup file if required, or append to it */
  5135. /* create actual filename from character name (same as used for sf_delete or process_player_name) */
  5136. k = 0;
  5137. for (j = 0; name[j]; j++) {
  5138. c = name[j];
  5139. /* Accept some letters */
  5140. if (isalpha(c) || isdigit(c)) savefile[k++] = c;
  5141. /* Convert space, dot, and underscore to underscore */
  5142. else if (strchr(SF_BAD_CHARS, c)) savefile[k++] = '_';
  5143. }
  5144. savefile[k] = '\0';
  5145. /* build path name and try to create/append to player's backup file */
  5146. path_build(buf, MAX_PATH_LENGTH, buf2, savefile);
  5147. if ((fp = fopen(buf, "rb")) == NULL)
  5148. newly_created = TRUE;
  5149. else {
  5150. newly_created = FALSE;
  5151. fclose(fp);
  5152. }
  5153. if ((fp = fopen(buf, "ab")) == NULL) {
  5154. s_printf(" error: cannot open file '%s'.\nfailed.\n", buf);
  5155. return FALSE;
  5156. } else if (newly_created) {
  5157. newly_created = FALSE;
  5158. /* begin with a version tag */
  5159. fprintf(fp, "%s\n", ESTATE_BACKUP_VERSION);
  5160. #if 0 /* guild info is no longer tied to map reset! */
  5161. /* add 2M Au if he's a guild master, since guilds will be erased if the server
  5162. savefile gets deleted (which is the sole purpose of calling this function..) */
  5163. for (j = 0; j < MAX_GUILDS; j++)
  5164. if (guilds[j].master == h_ptr->dna->owner) {
  5165. fprintf(fp, "AU:%d\n", GUILD_PRICE);
  5166. s_printf(" guild master: '%s'.\n", name);
  5167. break;
  5168. }
  5169. #endif
  5170. }
  5171. /* add house price to his backup file */
  5172. fprintf(fp, "AU:%d\n", au);
  5173. /* scan house contents and add them to his backup file */
  5174. /* traditional house? */
  5175. if (h_ptr->flags & HF_TRAD) {
  5176. for (j = 0; j < h_ptr->stock_num; j++) {
  5177. o_ptr = &h_ptr->stock[j];
  5178. /* add object to backup file */
  5179. fprintf(fp, "OB:");
  5180. fwrite(o_ptr, sizeof(object_type), 1, fp);
  5181. /* store inscription too! */
  5182. if (o_ptr->note) {
  5183. fprintf(fp, "%d\n", (int)strlen(quark_str(o_ptr->note)));
  5184. fwrite(quark_str(o_ptr->note), sizeof(char), strlen(quark_str(o_ptr->note)), fp);
  5185. } else
  5186. fprintf(fp, "%d\n", -1);
  5187. }
  5188. }
  5189. /* mang-style house? */
  5190. else {
  5191. /* allocate sector of the house to access objects */
  5192. if (!(zcave = getcave(wpos))) {
  5193. alloc_dungeon_level(wpos);
  5194. wilderness_gen(wpos);
  5195. if (!(zcave = getcave(wpos))) {
  5196. s_printf(" error: cannot getcave(%d,%d,%d).\nfailed.\n", wpos->wx, wpos->wy, wpos->wz);
  5197. fclose(fp);
  5198. return FALSE;
  5199. }
  5200. allocated = TRUE;
  5201. } else allocated = FALSE;
  5202. if (h_ptr->flags & HF_RECT) {
  5203. sy = h_ptr->y + 1;
  5204. sx = h_ptr->x + 1;
  5205. ey = h_ptr->y + h_ptr->coords.rect.height - 1;
  5206. ex = h_ptr->x + h_ptr->coords.rect.width - 1;
  5207. for (y = sy; y < ey; y++) {
  5208. for (x = sx; x < ex; x++) {
  5209. c_ptr = &zcave[y][x];
  5210. if (c_ptr->o_idx) {
  5211. o_ptr = &o_list[c_ptr->o_idx];
  5212. /* add object to backup file */
  5213. fprintf(fp, "OB:");
  5214. fwrite(o_ptr, sizeof(object_type), 1, fp);
  5215. /* store inscription too! */
  5216. if (o_ptr->note) {
  5217. fprintf(fp, "%d\n", (int)strlen(quark_str(o_ptr->note)));
  5218. fwrite(quark_str(o_ptr->note), sizeof(char), strlen(quark_str(o_ptr->note)), fp);
  5219. } else
  5220. fprintf(fp, "%d\n", -1);
  5221. }
  5222. }
  5223. }
  5224. } else {
  5225. /* Polygonal house */
  5226. //fill_house(h_ptr, FILL_CLEAR, NULL);
  5227. }
  5228. if (allocated) dealloc_dungeon_level(wpos);
  5229. }
  5230. /* done with this particular house */
  5231. fclose(fp);
  5232. }
  5233. s_printf("done.\n");
  5234. return TRUE;
  5235. }
  5236. /* helper function for restore_estate():
  5237. copy all remaining data from our save file to the temporary file
  5238. and turn the temporary file into the new save file. */
  5239. void relay_estate(char *buf, char *buf2, FILE *fp, FILE *fp_tmp) {
  5240. int c;
  5241. /* relay the remaining data, if any */
  5242. while ((c = fgetc(fp)) != EOF) fputc(c, fp_tmp);
  5243. /* done */
  5244. fclose(fp);
  5245. fclose(fp_tmp);
  5246. /* erase old save file, make temporary file the new save file */
  5247. remove(buf);
  5248. rename(buf2, buf);
  5249. }
  5250. /* get back the backed-up real estate from files */
  5251. void restore_estate(int Ind) {
  5252. player_type *p_ptr = Players[Ind];
  5253. FILE *fp, *fp_tmp;
  5254. char buf[MAX_PATH_LENGTH], buf2[MAX_PATH_LENGTH], version[MAX_CHARS];
  5255. char data[4], data_note[MSG_LEN];//MAX_OLEN?
  5256. char o_name[MSG_LEN];
  5257. unsigned long au;
  5258. int data_len;
  5259. object_type forge, *o_ptr = &forge;
  5260. bool gained_anything = FALSE;
  5261. s_printf("Restoring real estate for %s...\n", p_ptr->name);
  5262. /* create folder lib/save/estate if not existing */
  5263. path_build(buf2, MAX_PATH_LENGTH, ANGBAND_DIR_SAVE, "estate");
  5264. /* build path name and try to create/append to player's backup file */
  5265. path_build(buf, MAX_PATH_LENGTH, buf2, p_ptr->basename);
  5266. if ((fp = fopen(buf, "rb")) == NULL) {
  5267. s_printf(" error: No file '%s' exists to request from.\nfailed.\n", buf);
  5268. msg_print(Ind, "\377yNo goods or money stored to request.");
  5269. return;
  5270. }
  5271. s_printf(" opened file '%s'.\n", buf);
  5272. /* Try to read version string */
  5273. if (fgets(version, MAX_CHARS, fp) == NULL) {
  5274. s_printf(" error: File is empty.\nfailed.\n");
  5275. msg_print(Ind, "\377oAn error occurred, please contact an administrator.");
  5276. fclose(fp);
  5277. return;
  5278. }
  5279. version[strlen(version) - 1] = '\0';
  5280. s_printf(" reading a version '%s' estate file.\n", version);
  5281. /* open temporary file for writing the stuff the player left over */
  5282. strcpy(buf2, buf);
  5283. strcat(buf2, ".$$$");
  5284. if ((fp_tmp = fopen(buf2, "wb")) == NULL) {
  5285. s_printf(" error: cannot open temporary file '%s'.\nfailed.\n", buf2);
  5286. msg_print(Ind, "\377oAn error occurred, please contact an administrator.");
  5287. fclose(fp);
  5288. return;
  5289. }
  5290. /* relay to temporary file */
  5291. fprintf(fp_tmp, "%s\n", version);
  5292. msg_print(Ind, "\377yChecking for money and items from estate stored for you...");
  5293. while (TRUE) {
  5294. /* scan file for either house price (AU:) or object (OB:) */
  5295. if (!fread(data, sizeof(char), 3, fp)) {
  5296. if (!gained_anything) {
  5297. s_printf(" nothing to request.\ndone.\n");
  5298. msg_print(Ind, "\377yNo goods or money left to request.");
  5299. } else {
  5300. s_printf("done.\n");
  5301. msg_print(Ind, "\377yYou received everything that was stored for you.");
  5302. }
  5303. relay_estate(buf, buf2, fp, fp_tmp);
  5304. return;
  5305. }
  5306. data[3] = '\0';
  5307. /* get house price from backup file */
  5308. if (!strcmp(data, "AU:")) {
  5309. au = 0;
  5310. fscanf(fp, "%lu\n", &au);
  5311. if (!au) {
  5312. s_printf(" error: Corrupted AU: line.\n");
  5313. msg_print(Ind, "\377oAn error occurred, please contact an administrator.");
  5314. relay_estate(buf, buf2, fp, fp_tmp);
  5315. return;
  5316. }
  5317. /* give gold to player if it doesn't overflow,
  5318. otherwise relay rest to temporary file, swap and exit */
  5319. if (!gain_au(Ind, au, FALSE, FALSE)) {
  5320. msg_print(Ind, "\377yDrop/deposite some gold to be able to receive more gold.");
  5321. /* write failed gold gain back into new buffer file */
  5322. fprintf(fp_tmp, "AU:%lu\n", au);
  5323. relay_estate(buf, buf2, fp, fp_tmp);
  5324. return;
  5325. }
  5326. gained_anything = TRUE;
  5327. s_printf(" gained %d Au.\n", au);
  5328. msg_format(Ind, "You receive %d gold pieces.", au);
  5329. continue;
  5330. }
  5331. /* get object from backup file */
  5332. else if (!strcmp(data, "OB:")) {
  5333. fread(o_ptr, sizeof(object_type), 1, fp);
  5334. /* Update item's kind-index in case k_info.txt has been modified */
  5335. o_ptr->k_idx = lookup_kind(o_ptr->tval, o_ptr->sval);
  5336. #ifdef SEAL_INVALID_OBJECTS
  5337. if (!seal_or_unseal_object(o_ptr)) continue;
  5338. #endif
  5339. /* also read inscription */
  5340. o_ptr->note = 0;
  5341. data_len = -2;
  5342. #if 0 /* scanf() sucks a bit */
  5343. data_note[0] = '\0';
  5344. fscanf(fp, "%d[^\n]", &data_len);
  5345. fread(data_note, 1, 1, fp); //strip the \n that fscanf had to miss
  5346. #else
  5347. fgets(data_note, 4, fp);
  5348. data_len = atoi(data_note);
  5349. data_note[0] = '\0';
  5350. #endif
  5351. if (data_len == -2) {
  5352. object_desc(Ind, o_name, o_ptr, TRUE, 3);
  5353. s_printf(" error: Corrupted note line (item '%s').\n", o_name);
  5354. msg_print(Ind, "\377oAn error occurred, please contact an administrator.");
  5355. relay_estate(buf, buf2, fp, fp_tmp);
  5356. return;
  5357. }
  5358. if (data_len != -1) {
  5359. fread(data_note, sizeof(char), data_len, fp);
  5360. data_note[data_len] = '\0';
  5361. o_ptr->note = quark_add(data_note);
  5362. }
  5363. /* is it a pile of gold? */
  5364. if (o_ptr->tval == TV_GOLD) {
  5365. /* give gold to player if it doesn't overflow,
  5366. otherwise relay rest to temporary file, swap and exit */
  5367. au = o_ptr->pval;
  5368. if (!gain_au(Ind, au, FALSE, FALSE)) {
  5369. msg_print(Ind, "\377yDrop/deposite some gold to be able to receive more gold.");
  5370. /* write failed gold gain back into new buffer file */
  5371. fprintf(fp_tmp, "OB:");
  5372. fwrite(o_ptr, sizeof(object_type), 1, fp_tmp);
  5373. /* paranoia: should always be inscriptionless of course */
  5374. /* ..and its inscription */
  5375. if (o_ptr->note) {
  5376. fprintf(fp_tmp, "%d\n", (int)strlen(quark_str(o_ptr->note)));
  5377. fwrite(quark_str(o_ptr->note), sizeof(char), strlen(quark_str(o_ptr->note)), fp_tmp);
  5378. } else
  5379. fprintf(fp_tmp, "%d\n", -1);
  5380. relay_estate(buf, buf2, fp, fp_tmp);
  5381. return;
  5382. }
  5383. gained_anything = TRUE;
  5384. s_printf(" gained %d Au.\n", au);
  5385. msg_format(Ind, "You receive %d gold pieces.", au);
  5386. continue;
  5387. }
  5388. /* give item to player if he has space left,
  5389. otherwise relay rest to temporary file, swap and exit */
  5390. if (!inven_carry_okay(Ind, o_ptr)) {
  5391. msg_print(Ind, "\377yYour inventory is full, make some space to receive more items.");
  5392. /* write failed item back into new buffer file */
  5393. fprintf(fp_tmp, "OB:");
  5394. fwrite(o_ptr, sizeof(object_type), 1, fp_tmp);
  5395. /* ..and its inscription */
  5396. if (o_ptr->note) {
  5397. fprintf(fp_tmp, "%d\n", (int)strlen(quark_str(o_ptr->note)));
  5398. fwrite(quark_str(o_ptr->note), sizeof(char), strlen(quark_str(o_ptr->note)), fp_tmp);
  5399. } else
  5400. fprintf(fp_tmp, "%d\n", -1);
  5401. relay_estate(buf, buf2, fp, fp_tmp);
  5402. return;
  5403. }
  5404. gained_anything = TRUE;
  5405. inven_carry(Ind, o_ptr);
  5406. object_desc(Ind, o_name, o_ptr, TRUE, 3);
  5407. msg_format(Ind, "You receive %s.", o_name);
  5408. s_printf(" gained %s.\n", o_name);
  5409. continue;
  5410. } else {
  5411. s_printf(" invalid data '%s'.\n", data);
  5412. msg_print(Ind, "\377oAn error occurred, please contact an administrator.");
  5413. relay_estate(buf, buf2, fp, fp_tmp);
  5414. return;
  5415. }
  5416. }
  5417. }