Crossfire Server, Branches 1.12  R18729
readable.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_readable_c =
3  * "$Id: readable.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The authors can be reached via e-mail at crossfire-devel@real-time.com
27 */
28 
38 /* laid down initial file - dec 1995. -b.t. thomas@astro.psu.edu */
39 
40 #include <stdio.h>
41 #include <global.h>
42 #include <book.h>
43 #include <living.h>
44 #include <spells.h>
45 
46 /* Define this if you want to archive book titles by contents.
47  * This option should enforce UNIQUE combinations of titles,authors and
48  * msg contents during and *between *game sessions.
49  * Note: a slight degeneracy exists since books are archived based on an integer
50  * index value calculated from the message text (similar to alchemy formulae).
51  * Sometimes two widely different messages have the same index value (rare). In
52  * this case, it is possible to occasionally generate 2 books with same title and
53  * different message content. Not really a bug, but rather a feature. This action
54  * should keeps player on their toes ;).
55  * Also, note that there is *finite *space available for archiving message and titles.
56  * Once this space is used, books will stop being archived. Not a serious problem
57  * under the current regime, since there are generally fewer possible (random)
58  * messages than space available on the titlelists.
59  * One exception (for sure) are the monster messages. But no worries, you should
60  * see all of the monster info in some order (but not all possble combinations)
61  * before the monster titlelist space is run out. You can increase titlelist
62  * space by increasing the array sizes for the monster book_authours and book_names
63  * (see max_titles[] array and include/read.h). Since the unique_book algorthm is
64  * kinda stupid, this program *may *slow down program execution if defined (but I don't
65  * think its a significant problem, at least, I have no problems running this option
66  * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg
67  * combinations have been generated, unique_book isnt called anymore. It takes 5-10
68  * sessions for this to happen).
69  * Final note: the game remembers book/title/msg combinations from reading the
70  * file lib/bookarch. If you REMOVE this file, you will lose your archive. So
71  * be sure to copy it over to the new lib directory when you change versions.
72  * -b.t.
73  */
74 
75 /* This flag is useful to see what kind of output messages are created */
76 /* #define BOOK_MSG_DEBUG */
77 
78 /* This flag is useful for debugging archiving action */
79 /* #define ARCHIVE_DEBUG */
80 
82 #define MAX_TITLE_CHECK 20
83 
84 #define MSGTYPE_LIB 0
85 #define MSGTYPE_MONSTER 1
86 #define MSGTYPE_ARTIFACT 2
87 #define MSGTYPE_SPELLPATH 3
88 #define MSGTYPE_ALCHEMY 4
89 #define MSGTYPE_GODS 5
90 #define MSGTYPE_MSGFILE 6
91 
97 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
98 
99 /* Moved these structures from struct.h to this file in 0.94.3 - they
100  * are not needed anyplace else, so why have them globally declared?
101  */
102 
104 typedef struct titlestruct {
105  const char *name;
106  const char *authour;
107  const char *archname;
108  int level;
109  size_t size;
110  int msg_index;
111  struct titlestruct *next;
112 } title;
113 
114 typedef struct titleliststruct {
115  int number;
118 } titlelist;
119 
121 typedef struct namebytype {
122  const char *name;
123  int type;
124 } arttypename;
125 
126 static void add_book(title *book, int type, const char *fname, int lineno);
127 
132 static titlelist *booklist = NULL;
133 
135 static objectlink *first_mon_info = NULL;
136 
141 static int nrofmon = 0, need_to_write_bookarchive = 0;
142 
147 static int nrofmsg = 0;
148 
153 static linked_char *first_msg = NULL;
154 
159  PATH_PROT,
160  PATH_FIRE,
161  PATH_FROST,
162  PATH_ELEC,
163  PATH_MISSILE,
164  PATH_SELF,
165  PATH_SUMMON,
166  PATH_ABJURE,
167  PATH_RESTORE,
169  PATH_MIND,
170  PATH_CREATE,
171  PATH_TELE,
172  PATH_INFO,
175  PATH_TURNING,
177  PATH_DEATH,
178  PATH_LIGHT
179 };
180 
182 static const char *const path_book_name[] = {
183  "codex",
184  "compendium",
185  "exposition",
186  "tables",
187  "treatise"
188 };
189 
191 static const char *const path_author[] = {
192  "aether",
193  "astral byways",
194  "connections",
195  "the Grey Council",
196  "deep pathways",
197  "knowledge",
198  "magic",
199  "mystic ways",
200  "pathways",
201  "power",
202  "spells",
203  "transforms",
204  "the mystic veil",
205  "unknown spells"
206 };
207 
214 static const arttypename art_name_array[] = {
215  { "Helmet", HELMET },
216  { "Amulet", AMULET },
217  { "Shield", SHIELD },
218  { "Bracers", BRACERS },
219  { "Boots", BOOTS },
220  { "Cloak", CLOAK },
221  { "Gloves", GLOVES },
222  { "Gridle", GIRDLE },
223  { "Ring", RING },
224  { "Horn", HORN },
225  { "Missile Weapon", BOW },
226  { "Missile", ARROW },
227  { "Hand Weapon", WEAPON },
228  { "Artifact", SKILL },
229  { "Food", FOOD },
230  { "Body Armour", ARMOUR }
231 };
232 
234 static const char *const art_book_name[] = {
235  "collection",
236  "file",
237  "files",
238  "guide",
239  "handbook",
240  "index",
241  "inventory",
242  "list",
243  "listing",
244  "record",
245  "record book"
246 };
247 
249 static const char *const art_author[] = {
250  "ancient things",
251  "artifacts",
252  "Havlor", /* ancient warrior scribe :) */
253  "items",
254  "lost artifacts",
255  "the ancients",
256  "useful things"
257 };
258 
262 static const char *const mon_book_name[] = {
263  "beastuary",
264  "catalog",
265  "compilation",
266  "collection",
267  "encyclopedia",
268  "guide",
269  "handbook",
270  "list",
271  "manual",
272  "notes",
273  "record",
274  "register",
275  "volume"
276 };
277 
279 static const char *const mon_author[] = {
280  "beasts",
281  "creatures",
282  "dezidens",
283  "dwellers",
284  "evil nature",
285  "life",
286  "monsters",
287  "nature",
288  "new life",
289  "residents",
290  "the spawn",
291  "the living",
292  "things"
293 };
294 
298 static const char *const gods_book_name[] = {
299  "devotional",
300  "devout notes",
301  "divine text",
302  "divine work",
303  "holy book",
304  "holy record",
305  "moral text",
306  "sacred guide",
307  "testament",
308  "transcript"
309 };
310 
312 static const char *const gods_author[] = {
313  "cults",
314  "joy",
315  "lasting curse",
316  "madness",
317  "religions",
318  "the dead",
319  "the gods",
320  "the heirophant",
321  "the poor priest",
322  "the priestess",
323  "pain",
324  "white"
325 };
326 
330 static const char *const formula_book_name[] = {
331  "cookbook",
332  "formulary",
333  "lab book",
334  "lab notes",
335  "recipe book",
336  "experiment record",
337  "work plan",
338  "design notes"
339 };
340 
342 static const char *const formula_author[] = {
343  "Albertus Magnus",
344  "alchemy",
345  "balms",
346  "creation",
347  "dusts",
348  "magical manufacture",
349  "making",
350  "philosophical items",
351  "potions",
352  "powders",
353  "the cauldron",
354  "the lamp black",
355  "transmutation",
356  "waters"
357 };
358 
364 static const char *const light_book_name[] = {
365  "calendar",
366  "datebook",
367  "diary",
368  "guidebook",
369  "handbook",
370  "ledger",
371  "notes",
372  "notebook",
373  "octavo",
374  "pamphlet",
375  "practicum",
376  "script",
377  "transcript"
378 };
379 
381 static const char *const heavy_book_name[] = {
382  "catalog",
383  "compendium",
384  "guide",
385  "manual",
386  "opus",
387  "tome",
388  "treatise",
389  "volume",
390  "work"
391 };
392 
394 static const char *const book_author[] = {
395  "Abdulah",
396  "Al'hezred",
397  "Alywn",
398  "Arundel",
399  "Arvind",
400  "Aerlingas",
401  "Bacon",
402  "Baliqendii",
403  "Bosworth",
404  "Beathis",
405  "Bertil",
406  "Cauchy",
407  "Chakrabarti",
408  "der Waalis",
409  "Dirk",
410  "Djwimii",
411  "Eisenstaadt",
412  "Fendris",
413  "Frank",
414  "Habbi",
415  "Harlod",
416  "Ichibod",
417  "Janus",
418  "June",
419  "Magnuson",
420  "Nandii",
421  "Nitfeder",
422  "Norris",
423  "Parael",
424  "Penhew",
425  "Sophia",
426  "Skilly",
427  "Tahir",
428  "Thockmorton",
429  "Thomas",
430  "van Helsing",
431  "van Pelt",
432  "Voormis",
433  "Xavier",
434  "Xeno",
435  "Zardoz",
436  "Zagy"
437 };
438 
440 static const char *const book_descrpt[] = {
441  "ancient",
442  "cryptic",
443  "cryptical",
444  "dusty",
445  "hiearchical",
446  "grizzled",
447  "gold-guilt",
448  "great",
449  "lost",
450  "magnificent",
451  "musty",
452  "mythical",
453  "mystical",
454  "rustic",
455  "stained",
456  "silvered",
457  "transcendental",
458  "weathered"
459 };
460 
468  /*subtype 0 */ { 0, 0 },
469  /* book messages subtypes */
470  /*subtype 1 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1 },
479  /*subtype 10 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER },
481  /* card messages subtypes*/
490  /*subtype 20 */ { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3 },
494 
495  /* Paper messages subtypes */
502  /*subtype 30 */ { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2 },
510 
511  /* road signs messages subtypes */
514  /*subtype 40 */ { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT },
516 
517  /* stones and monument messages */
530 };
531 
533 static const int last_readable_subtype = arraysize(readable_message_types);
534 
536 static const int max_titles[6] = {
538  arraysize(mon_book_name)*arraysize(mon_author), /* MSGTYPE_MONSTER */
539  arraysize(art_book_name)*arraysize(art_author), /* MSGTYPE_ARTIFACT */
540  arraysize(path_book_name)*arraysize(path_author), /* MSGTYPE_SPELLPATH */
541  arraysize(formula_book_name)*arraysize(formula_author), /* MSGTYPE_ALCHEMY */
542  arraysize(gods_book_name)*arraysize(gods_author), /* MSGTYPE_GODS */
543 };
544 
545 /******************************************************************************
546  *
547  * Start of misc. readable functions used by others functions in this file
548  *
549  *****************************************************************************/
550 
561  titlelist *bl = (titlelist *)malloc(sizeof(titlelist));
562 
563  if (bl == NULL)
565  bl->number = 0;
566  bl->first_book = NULL;
567  bl->next = NULL;
568  return bl;
569 }
570 
580 static title *get_empty_book(void) {
581  title *t = (title *)malloc(sizeof(title));
582 
583  if (t == NULL)
585  t->name = NULL;
586  t->archname = NULL;
587  t->authour = NULL;
588  t->level = 0;
589  t->size = 0;
590  t->msg_index = 0;
591  t->next = NULL;
592  return t;
593 }
594 
605 static titlelist *get_titlelist(int i) {
606  titlelist *tl;
607  int number;
608 
609  if (i < 0 || i >= (int)arraysize(max_titles)) {
610  LOG(llevInfo, "Warning: invalid book index %d, using 0 instead\n", i);
611  return booklist;
612  }
613 
614  for (tl = booklist, number = i; tl && number; tl = tl->next, number--) {
615  if (!tl->next)
616  tl->next = get_empty_booklist();
617  }
618 
619  return tl;
620 }
621 
622 /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file
623  * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
624 
636 static int nstrtok(const char *buf1, const char *buf2) {
637  char *tbuf, buf[MAX_BUF];
638  int number = 0;
639 
640  if (!buf1 || !buf2)
641  return 0;
642 
643  snprintf(buf, sizeof(buf), "%s", buf1);
644  for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
645  number++;
646  }
647  return number;
648 }
649 
666 static char *strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size) {
667  int maxi, i = nstrtok(buf1, buf2);
668  char *tbuf, buf[MAX_BUF];
669 
670  maxi = i;
671  snprintf(buf, sizeof(buf), "%s", buf1);
672  snprintf(retbuf, size, " ");
673  for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
674  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "%s", tbuf);
675  i--;
676  if (i == 1 && maxi > 1)
677  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), " and ");
678  else if (i > 0 && maxi > 1)
679  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ", ");
680  else
681  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ".");
682  }
683  return retbuf;
684 }
685 
696 int book_overflow(const char *buf1, const char *buf2, size_t booksize) {
697  if (buf_overflow(buf1, buf2, BOOK_BUF-2) /* 2 less so always room for trailing \n */
698  || buf_overflow(buf1, buf2, booksize))
699  return 1;
700  return 0;
701 }
702 
703 /*****************************************************************************
704  *
705  * Start of initialization related functions.
706  *
707  ****************************************************************************/
708 
714 static void init_msgfile(void) {
715  FILE *fp;
716  char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp;
717  int comp;
718  static int did_init_msgfile = 0;
719 
720  if (did_init_msgfile)
721  return;
722  did_init_msgfile = 1;
723 
724  snprintf(fname, sizeof(fname), "%s/messages", settings.datadir);
725  LOG(llevDebug, "Reading messages from %s...\n", fname);
726 
727  fp = open_and_uncompress(fname, 0, &comp);
728  if (fp != NULL) {
729  linked_char *tmp = NULL;
730  int lineno;
731  int error_lineno;
732 
733  error_lineno = 0;
734  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
735  if (*buf == '#')
736  continue;
737  cp = strchr(buf, '\n');
738  if (cp != NULL) {
739  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
740  cp--;
741  *cp = '\0';
742  }
743  if (tmp != NULL) {
744  if (strcmp(buf, "ENDMSG") == 0) {
745  if (strlen(msgbuf) > BOOK_BUF) {
746  LOG(llevDebug, "Warning: this string exceeded max book buf size:\n");
747  LOG(llevDebug, " %s\n", msgbuf);
748  }
749  tmp->name = add_string(msgbuf);
750  tmp->next = first_msg;
751  first_msg = tmp;
752  nrofmsg++;
753  tmp = NULL;
754  } else if (!buf_overflow(msgbuf, buf, HUGE_BUF-1)) {
755  strcat(msgbuf, buf);
756  strcat(msgbuf, "\n");
757  } else if (error_lineno != 0) {
758  LOG(llevInfo, "Warning: truncating book at %s, line %d\n", fname, error_lineno);
759  error_lineno = 0;
760  }
761  } else if (strcmp(buf, "MSG") == 0) {
762  error_lineno = lineno;
763  tmp = (linked_char *)malloc(sizeof(linked_char));
764  strcpy(msgbuf, " "); /* reset msgbuf for new message */
765  } else {
766  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
767  }
768  }
769  close_and_delete(fp, comp);
770  }
771 
772 #ifdef BOOK_MSG_DEBUG
773  LOG(llevDebug, "init_info_listfile() got %d messages.\n", nrofmsg);
774 #endif
775  LOG(llevDebug, "done messages.\n");
776 }
777 
784 static void init_book_archive(void) {
785  FILE *fp;
786  int comp, nroftitle = 0;
787  char buf[MAX_BUF], fname[MAX_BUF], *cp;
788  static int did_init_barch = 0;
789 
790  if (did_init_barch)
791  return;
792  did_init_barch = 1;
793 
794  if (!booklist)
795  booklist = get_empty_booklist();
796 
797  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
798  LOG(llevDebug, " Reading bookarch from %s...\n", fname);
799 
800  fp = open_and_uncompress(fname, 0, &comp);
801  if (fp != NULL) {
802  int type;
803  size_t i;
804  titlelist *bl;
805  int lineno;
806  title *book;
807  int skipping;
808 
809  skipping = 0;
810  book = NULL;
811  type = -1;
812  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
813  int len;
814  int value;
815 
816  if (*buf == '#')
817  continue;
818  cp = strchr(buf, '\n');
819  if (cp != NULL) {
820  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
821  cp--;
822  *cp = '\0';
823  }
824  cp = buf;
825  if (strncmp(buf, "title ", 6) == 0) {
826  skipping = 0;
827  cp = buf+6;
828  while (*cp == ' ' || *cp == '\t')
829  cp++;
830  if (*cp == '\0') {
831  LOG(llevInfo, "Warning: missing book title at %s, line %d\n", fname, lineno);
832  book = NULL;
833  } else {
834  book = get_empty_book(); /* init new book entry */
835  book->name = add_string(cp);
836  type = -1;
837  nroftitle++;
838  }
839  } else if (book == NULL) {
840  if (!skipping) {
841  skipping = 1;
842  LOG(llevInfo, "Warning: expecting 'title' at %s, line %d\n", fname, lineno);
843  }
844  } else if (strncmp(buf, "authour ", 8) == 0) {
845  cp = buf+8;
846  while (*cp == ' ' || *cp == '\t')
847  cp++;
848  if (*cp == '\0') {
849  LOG(llevInfo, "Warning: missing book authour at %s, line %d\n", fname, lineno);
850  } else {
851  book->authour = add_string(cp);
852  }
853  } else if (strncmp(buf, "arch ", 5) == 0) {
854  cp = buf+5;
855  while (*cp == ' ' || *cp == '\t')
856  cp++;
857  if (*cp == '\0') {
858  LOG(llevInfo, "Warning: missing book arch at %s, line %d\n", fname, lineno);
859  } else {
860  book->archname = add_string(cp);
861  }
862  } else if (sscanf(buf, "level %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
863  book->level = value;
864  } else if (sscanf(buf, "type %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
865  type = value;
866  } else if (sscanf(buf, "size %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
867  book->size = value;
868  } else if (sscanf(buf, "index %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
869  book->msg_index = value;
870  } else if (strcmp(buf, "end") == 0) { /* link it */
871  add_book(book, type, fname, lineno);
872  book = NULL;
873  type = -1;
874  } else {
875  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
876  }
877  }
878  if (book != NULL) {
879  LOG(llevInfo, "Warning: missing 'end' at %s, line %d\n", fname, lineno);
880  add_book(book, type, fname, lineno);
881  }
882  LOG(llevDebug, " book archives(used/avail):\n");
883  for (bl = booklist, i = 0; bl != NULL && i < arraysize(max_titles); bl = bl->next, i++) {
884  LOG(llevDebug, "(%d/%d)\n", bl->number, max_titles[i]);
885  }
886  close_and_delete(fp, comp);
887  }
888 
889 #ifdef BOOK_MSG_DEBUG
890  LOG(llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle);
891 #endif
892  LOG(llevDebug, " done.\n");
893 }
894 
902 static void add_book(title *book, int type, const char *fname, int lineno) {
903  titlelist *bl;
904 
905  if (type == -1) {
906  LOG(llevInfo, "Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
907  type = 0;
908  }
909 
910  bl = get_titlelist(type);
911  book->next = bl->first_book;
912  bl->first_book = book;
913  bl->number++;
914 }
915 
920 static void init_mon_info(void) {
921  archetype *at;
922  static int did_init_mon_info = 0;
923 
924  if (did_init_mon_info)
925  return;
926  did_init_mon_info = 1;
927 
928  for (at = first_archetype; at != NULL; at = at->next) {
929  if (QUERY_FLAG(&at->clone, FLAG_MONSTER)
931  objectlink *mon = (objectlink *)malloc(sizeof(objectlink));
932  if (!mon) {
933  LOG(llevError, "init_mon_info: malloc failed!\n");
934  abort();
935  }
936  mon->ob = &at->clone;
937  mon->id = nrofmon;
938  mon->next = first_mon_info;
939  first_mon_info = mon;
940  nrofmon++;
941  }
942  }
943  LOG(llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
944 }
945 
952 void init_readable(void) {
953  static int did_this = 0;
954 
955  if (did_this)
956  return;
957  did_this = 1;
958 
959  LOG(llevDebug, "Initializing reading data...\n");
960  init_msgfile();
962  init_mon_info();
963  LOG(llevDebug, " done reading data\n");
964 }
965 
966 /*****************************************************************************
967  *
968  * This is the start of the administrative functions when creating
969  * new books (ie, updating title and the like)
970  *
971  *****************************************************************************/
972 
984 static title *find_title(const object *book, int msgtype) {
985  title *t;
986  titlelist *tl;
987  size_t length;
988  int index;
989 
990  if (msgtype < 0)
991  return (title *)NULL;
992 
993  tl = get_titlelist(msgtype);
994  if (!tl)
995  return (title *)NULL;
996 
997  length = strlen(book->msg);
998  index = strtoint(book->msg);
999  for (t = tl->first_book; t; t = t->next)
1000  if (t->size == length && t->msg_index == index) {
1001 #ifdef ARCHIVE_DEBUG
1002  LOG(llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
1003 #endif
1004  return t;
1005  }
1006 
1007  return (title *)NULL;
1008 }
1009 
1023 static void new_text_name(object *book, int msgtype) {
1024  const char *name;
1025 
1026  if (book->type != BOOK)
1027  return;
1028 
1029  switch (msgtype) {
1030  case MSGTYPE_MONSTER:
1031  name = mon_book_name[RANDOM()%arraysize(mon_book_name)];
1032  break;
1033 
1034  case MSGTYPE_ARTIFACT:
1035  name = art_book_name[RANDOM()%arraysize(art_book_name)];
1036  break;
1037 
1038  case MSGTYPE_SPELLPATH:
1039  name = path_book_name[RANDOM()%arraysize(path_book_name)];
1040  break;
1041 
1042  case MSGTYPE_ALCHEMY:
1043  name = formula_book_name[RANDOM()%arraysize(formula_book_name)];
1044  break;
1045 
1046  case MSGTYPE_GODS:
1047  name = gods_book_name[RANDOM()%arraysize(gods_book_name)];
1048  break;
1049 
1050  case MSGTYPE_MSGFILE:
1051  default:
1052  if (book->weight > 2000) { /* based on weight */
1053  name = heavy_book_name[RANDOM()%arraysize(heavy_book_name)];
1054  } else {
1055  name = light_book_name[RANDOM()%arraysize(light_book_name)];
1056  }
1057  break;
1058  }
1059  free_string(book->name);
1060  book->name = add_string(name);
1061 }
1062 
1072 static void add_author(object *op, int msgtype) {
1073  char title[MAX_BUF];
1074  const char *name;
1075 
1076  if (msgtype < 0 || strlen(op->msg) < 5)
1077  return;
1078 
1079  switch (msgtype) {
1080  case MSGTYPE_MONSTER:
1081  name = mon_author[RANDOM()%arraysize(mon_author)];
1082  break;
1083 
1084  case MSGTYPE_ARTIFACT:
1085  name = art_author[RANDOM()%arraysize(art_author)];
1086  break;
1087 
1088  case MSGTYPE_SPELLPATH:
1089  name = path_author[RANDOM()%arraysize(path_author)];
1090  break;
1091 
1092  case MSGTYPE_ALCHEMY:
1093  name = formula_author[RANDOM()%arraysize(formula_author)];
1094  break;
1095 
1096  case MSGTYPE_GODS:
1097  name = gods_author[RANDOM()%arraysize(gods_author)];
1098  break;
1099 
1100  case MSGTYPE_MSGFILE:
1101  default:
1102  name = book_author[RANDOM()%arraysize(book_author)];
1103  }
1104 
1105  snprintf(title, sizeof(title), "of %s", name);
1106  op->title = add_string(title);
1107 }
1108 
1120 static int unique_book(const object *book, int msgtype) {
1121  title *test;
1122 
1123  if (!booklist)
1124  return 1; /* No archival entries! Must be unique! */
1125 
1126  /* Go through the booklist. If the author and name match, not unique so
1127  * return 0.
1128  */
1129  for (test = get_titlelist(msgtype)->first_book; test; test = test->next) {
1130  if (!strcmp(test->name, book->name) && !strcmp(book->title, test->authour))
1131  return 0;
1132  }
1133  return 1;
1134 }
1135 
1144 static void add_book_to_list(const object *book, int msgtype) {
1145  titlelist *tl = get_titlelist(msgtype);
1146  title *t;
1147 
1148  if (!tl) {
1149  LOG(llevError, "add_book_to_list can't get booklist!\n");
1150  return;
1151  }
1152 
1153  t = get_empty_book();
1154  t->name = add_string(book->name);
1155  t->authour = add_string(book->title);
1156  t->size = strlen(book->msg);
1157  t->msg_index = strtoint(book->msg);
1158  t->archname = add_string(book->arch->name);
1159  t->level = book->level;
1160 
1161  t->next = tl->first_book;
1162  tl->first_book = t;
1163  tl->number++;
1164 
1165  /* We have stuff we need to write now */
1167 
1168 #ifdef ARCHIVE_DEBUG
1169  LOG(llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
1170 #endif
1171 }
1172 
1186 static void change_book(object *book, int msgtype) {
1187  titlelist *tl;
1188  title *t;
1189  int tries;
1190 
1191  if (book->type != BOOK) {
1192  LOG(llevError, "change_book_name() called w/ illegal obj type.\n");
1193  return;
1194  }
1195 
1196  tl = get_titlelist(msgtype);
1197  t = NULL;
1198  tries = 0;
1199 
1200  /* look to see if our msg already been archived. If so, alter
1201  * the book to match the archival text. If we fail to match,
1202  * then we archive the new title/name/msg combo if there is
1203  * room on the titlelist.
1204  */
1205 
1206  if (strlen(book->msg) > 5 && (t = find_title(book, msgtype))) {
1207  object *tmpbook;
1208 
1209  /* alter book properties */
1210  tmpbook = create_archetype(t->archname);
1211  if (tmpbook->msg)
1212  free_string(tmpbook->msg);
1213  tmpbook->msg = add_string(book->msg);
1214  copy_object(tmpbook, book);
1215  free_object(tmpbook);
1216 
1217  book->title = add_string(t->authour);
1218  free_string(book->name);
1219  book->name = add_string(t->name);
1220  book->level = t->level;
1221  } else { /* Don't have any default title, so lets make up a new one */
1222  int numb, maxnames = max_titles[msgtype];
1223  const char *old_title;
1224  const char *old_name;
1225 
1226  old_title = book->title ? add_string(book->title) : NULL;
1227  old_name = add_string(book->name);
1228 
1229  /* some pre-generated books have title already set (from
1230  * maps), also don't bother looking for unique title if
1231  * we already used up all the available names! */
1232 
1233  if (!tl) {
1234  LOG(llevError, "change_book_name(): can't find title list\n");
1235  numb = 0;
1236  } else
1237  numb = tl->number;
1238 
1239  if (numb == maxnames) {
1240 #ifdef ARCHIVE_DEBUG
1241  LOG(llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1242 #endif
1243  if (old_title != NULL)
1244  free_string(old_title);
1245  free_string(old_name);
1246  return;
1247  }
1248  /* shouldnt change map-maker books */
1249  if (!book->title)
1250  do {
1251  /* random book name */
1252  new_text_name(book, msgtype);
1253  add_author(book, msgtype); /* random author */
1254  tries++;
1255  } while (!unique_book(book, msgtype) && tries < MAX_TITLE_CHECK);
1256 
1257  /* Now deal with 2 cases.
1258  * 1) If no space for a new title exists lets just restore
1259  * the old book properties. Remember, if the book had
1260  * matchd an older entry on the titlelist, we shouldnt
1261  * have called this routine in the first place!
1262  * 2) If we got a unique title, we need to add it to
1263  * the list.
1264  */
1265 
1266  if (tries == MAX_TITLE_CHECK) {
1267 #ifdef ARCHIVE_DEBUG
1268  LOG(llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1269 #endif
1270  /* restore old book properties here */
1271  free_string(book->name);
1272  free_string(book->title);
1273  book->title = old_title != NULL ? add_string(old_title) : NULL;
1274 
1275  if (RANDOM()%4) {
1276  /* Lets give the book a description to individualize it some */
1277  char new_name[MAX_BUF];
1278 
1279  snprintf(new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM()%arraysize(book_descrpt)], old_name);
1280  book->name = add_string(new_name);
1281  } else {
1282  book->name = add_string(old_name);
1283  }
1284  } else if (book->title && strlen(book->msg) > 5) { /* archive if long msg texts */
1285  add_book_to_list(book, msgtype);
1286  }
1287 
1288  if (old_title != NULL)
1289  free_string(old_title);
1290  free_string(old_name);
1291  }
1292 }
1293 
1294 /*****************************************************************************
1295  *
1296  * This is the start of the area that generates the actual contents
1297  * of the book.
1298  *
1299  *****************************************************************************/
1300 
1301 /*****************************************************************************
1302  * Monster msg generation code.
1303  ****************************************************************************/
1304 
1316 object *get_random_mon(int level) {
1317  objectlink *mon;
1318  int i, monnr;
1319 
1320  /* safety check. Problem w/ init_mon_info list? */
1321  if (!nrofmon || !first_mon_info)
1322  return (object *)NULL;
1323 
1324  if (!level) {
1325  /* lets get a random monster from the mon_info linked list */
1326  monnr = RANDOM()%nrofmon;
1327 
1328  for (mon = first_mon_info, i = 0; mon; mon = mon->next, i++)
1329  if (i == monnr)
1330  break;
1331 
1332  if (!mon) {
1333  LOG(llevError, "get_random_mon: Didn't find a monster when we should have\n");
1334  return NULL;
1335  }
1336  return mon->ob;
1337  }
1338 
1339  /* Case where we are searching by level. Redone 971225 to be clearer
1340  * and more random. Before, it looks like it took a random monster from
1341  * the list, and then returned the first monster after that which was
1342  * appropriate level. This wasn't very random because if you had a
1343  * bunch of low level monsters and then a high level one, if the random
1344  * determine took one of the low level ones, it would just forward to the
1345  * high level one and return that. Thus, monsters that immediately followed
1346  * a bunch of low level monsters would be more heavily returned. It also
1347  * means some of the dragons would be poorly represented, since they
1348  * are a group of high level monsters all around each other.
1349  */
1350 
1351  /* First count number of monsters meeting level criteria */
1352  for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1353  if (mon->ob->level >= level)
1354  i++;
1355 
1356  if (i == 0) {
1357  LOG(llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1358  return NULL;
1359  }
1360 
1361  monnr = RANDOM()%i;
1362  for (mon = first_mon_info; mon; mon = mon->next)
1363  if (mon->ob->level >= level && monnr-- == 0)
1364  return mon->ob;
1365 
1366  LOG(llevError, "get_random_mon(): didn't find a monster when we should have\n");
1367  return NULL;
1368 }
1369 
1383 static char *mon_desc(const object *mon, char *buf, size_t size) {
1384  snprintf(buf, size, " *** %s ***\n", mon->name);
1385  describe_item(mon, NULL, buf+strlen(buf), size-strlen(buf));
1386  return buf;
1387 }
1388 
1400 static object *get_next_mon(const object *tmp) {
1401  objectlink *mon;
1402 
1403  for (mon = first_mon_info; mon; mon = mon->next)
1404  if (mon->ob == tmp)
1405  break;
1406 
1407  /* didn't find a match */
1408  if (!mon)
1409  return NULL;
1410  if (mon->next)
1411  return mon->next->ob;
1412  else
1413  return first_mon_info->ob;
1414 }
1415 
1429 static char *mon_info_msg(int level, char *buf, size_t booksize) {
1430  char tmpbuf[HUGE_BUF], desc[MAX_BUF];
1431  object *tmp;
1432 
1433  /*preamble */
1434  snprintf(buf, booksize, "This beastiary contains:");
1435 
1436  /* lets print info on as many monsters as will fit in our
1437  * document.
1438  * 8-96 Had to change this a bit, otherwise there would
1439  * have been an impossibly large number of combinations
1440  * of text! (and flood out the available number of titles
1441  * in the archive in a snap!) -b.t.
1442  */
1443  for (tmp = get_random_mon(level*3); tmp; tmp = get_next_mon(tmp)) {
1444  /* monster description */
1445  snprintf(tmpbuf, sizeof(tmpbuf), "\n---\n%s", mon_desc(tmp, desc, sizeof(desc)));
1446 
1447  if (book_overflow(buf, tmpbuf, booksize))
1448  break;
1449  snprintf(buf+strlen(buf), booksize-strlen(buf), "%s", tmpbuf);
1450  }
1451 
1452 #ifdef BOOK_MSG_DEBUG
1453  LOG(llevDebug, "\n mon_info_msg() created strng: %d\n", strlen(retbuf));
1454  fprintf(logfile, " MADE THIS:\n%s\n", retbuf);
1455 #endif
1456 
1457  return buf;
1458 }
1459 
1460 /*****************************************************************************
1461  * Artifact msg generation code.
1462  ****************************************************************************/
1463 
1477 static char *artifact_msg(int level, char *retbuf, size_t booksize) {
1478  artifactlist *al;
1479  artifact *art;
1480  int chance, i, type, index;
1481  int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
1482  char buf[BOOK_BUF], sbuf[MAX_BUF];
1483  object *tmp;
1484 
1485  /* values greater than 5 create msg buffers that are too big! */
1486  if (book_entries > 5)
1487  book_entries = 5;
1488 
1489  /* lets determine what kind of artifact type randomly.
1490  * Right now legal artifacts only come from those listed
1491  * in art_name_array. Also, we check to be sure an artifactlist
1492  * for that type exists!
1493  */
1494  i = 0;
1495  do {
1496  index = RANDOM()%arraysize(art_name_array);
1497  type = art_name_array[index].type;
1498  al = find_artifactlist(type);
1499  i++;
1500  } while (al == NULL && i < 10);
1501 
1502  if (i == 10) { /* Unable to find a message */
1503  snprintf(retbuf, booksize, "None");
1504  return retbuf;
1505  }
1506 
1507  /* There is no reason to start on the artifact list at the beginning. Lets
1508  * take our starting position randomly... */
1509  art = al->items;
1510  for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
1511  if (art == NULL)
1512  art = al->items; /* hmm, out of stuff, loop back around */
1513  art = art->next;
1514  }
1515 
1516  /* Ok, lets print out the contents */
1517  snprintf(retbuf, booksize, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1518 
1519  /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1520  * as long as we have space up to the allowed max # (book_entires)
1521  */
1522  while (book_entries > 0) {
1523  if (art == NULL)
1524  art = al->items;
1525 
1526  /* separator of items */
1527  snprintf(buf, sizeof(buf), "---\n");
1528 
1529  /* Name */
1530  if (art->allowed != NULL && strcmp(art->allowed->name, "All")) {
1531  linked_char *temp, *next = art->allowed;
1532 
1533  do {
1534  temp = next;
1535  next = next->next;
1536  } while (next != (linked_char *)NULL && RANDOM()%2);
1537  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " A %s of %s", temp->name, art->item->name);
1538  } else { /* default name is used */
1539  /* use the base 'generic' name for our artifact */
1540  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " The %s of %s", art_name_array[index].name, art->item->name);
1541  }
1542 
1543  /* chance of finding */
1544  chance = 100*((float)art->chance/al->total_chance);
1545  if (chance >= 20)
1546  snprintf(sbuf, sizeof(sbuf), "an uncommon");
1547  else if (chance >= 10)
1548  snprintf(sbuf, sizeof(sbuf), "an unusual");
1549  else if (chance >= 5)
1550  snprintf(sbuf, sizeof(sbuf), "a rare");
1551  else
1552  snprintf(sbuf, sizeof(sbuf), "a very rare");
1553  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " is %s\n", sbuf);
1554 
1555  /* value of artifact */
1556  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " item with a value that is %d times normal.\n",
1557  art->item->value);
1558 
1559  /* include the message about the artifact, if exists, and book
1560  * level is kinda high */
1561  if (art->item->msg && RANDOM()%4+1 < level
1562  && !(strlen(art->item->msg)+strlen(buf) > BOOK_BUF))
1563  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", art->item->msg);
1564 
1565  /* properties of the artifact */
1566  tmp = get_object();
1567  add_abilities(tmp, art->item);
1568  tmp->type = type;
1569  SET_FLAG(tmp, FLAG_IDENTIFIED);
1570  describe_item(tmp, NULL, sbuf, sizeof(sbuf));
1571  if (strlen(sbuf) > 1)
1572  snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " Properties of this artifact include:\n %s\n", sbuf);
1573  free_object(tmp);
1574  /* add the buf if it will fit */
1575  if (book_overflow(retbuf, buf, booksize))
1576  break;
1577  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "%s", buf);
1578 
1579  art = art->next;
1580  book_entries--;
1581  }
1582 
1583 #ifdef BOOK_MSG_DEBUG
1584  LOG(llevDebug, "artifact_msg() created strng: %d\n", strlen(retbuf));
1585  fprintf(logfile, " MADE THIS:\n%s", retbuf);
1586 #endif
1587  return retbuf;
1588 }
1589 
1590 /*****************************************************************************
1591  * Spellpath message generation
1592  *****************************************************************************/
1593 
1607 static char *spellpath_msg(int level, char *retbuf, size_t booksize) {
1608  int path = RANDOM()%NRSPELLPATHS, prayers = RANDOM()%2;
1609  int did_first_sp = 0;
1610  uint32 pnum = spellpathdef[path];
1611  archetype *at;
1612 
1613  /* Preamble */
1614  snprintf(retbuf, booksize, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
1615 
1616  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "belonging to the path of %s:\n", spellpathnames[path]);
1617 
1618  for (at = first_archetype; at != NULL; at = at->next) {
1619  /* Determine if this is an appropriate spell. Must
1620  * be of matching path, must be of appropriate type (prayer
1621  * or not), and must be within the valid level range.
1622  */
1623  if (at->clone.type == SPELL
1624  && at->clone.path_attuned&pnum
1625  && ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers))
1626  && at->clone.level < level*8) {
1627  if (book_overflow(retbuf, at->clone.name, booksize))
1628  break;
1629 
1630  if (did_first_sp)
1631  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), ",\n");
1632  did_first_sp = 1;
1633  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "%s", at->clone.name);
1634  }
1635  }
1636  /* Geez, no spells were generated. */
1637  if (!did_first_sp) {
1638  if (RANDOM()%4) /* usually, lets make a recursive call... */
1639  return spellpath_msg(level, retbuf, booksize);
1640  /* give up, cause knowing no spells exist for path is info too. */
1641  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "\n - no known spells exist -\n");
1642  } else {
1643  snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "\n");
1644  }
1645  return retbuf;
1646 }
1647 
1656 static void make_formula_book(object *book, int level) {
1657  char retbuf[BOOK_BUF], title[MAX_BUF];
1658  recipelist *fl;
1659  recipe *formula;
1660  int chance;
1661  const char *op_name;
1662  archetype *at;
1663 
1664  /* the higher the book level, the more complex (ie number of
1665  * ingredients) the formula can be.
1666  */
1667  fl = get_formulalist((RANDOM()%level)/3+1);
1668  if (!fl)
1669  fl = get_formulalist(1); /* safety */
1670 
1671  if (fl->total_chance == 0) {
1672  book->msg = add_string(" <indecipherable text>\n");
1674  add_author(book, MSGTYPE_ALCHEMY);
1675  return;
1676  }
1677 
1678  /* get a random formula, weighted by its bookchance */
1679  chance = RANDOM()%fl->total_chance;
1680  for (formula = fl->items; formula != NULL; formula = formula->next) {
1681  chance -= formula->chance;
1682  if (chance <= 0)
1683  break;
1684  }
1685 
1686  if (!formula || formula->arch_names <= 0) {
1687  book->msg = add_string(" <indecipherable text>\n");
1689  add_author(book, MSGTYPE_ALCHEMY);
1690  return;
1691  }
1692 
1693  /* looks like a formula was found. Base the amount
1694  * of information on the booklevel and the spellevel
1695  * of the formula. */
1696 
1697  /* preamble */
1698  snprintf(retbuf, sizeof(retbuf), "Herein is described a project using %s:\n", formula->skill ? formula->skill : "an unknown skill");
1699 
1700  op_name = formula->arch_name[RANDOM()%formula->arch_names];
1701  at = find_archetype(op_name);
1702  if (at == (archetype *)NULL) {
1703  LOG(llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1704  book->msg = add_string(" <indecipherable text>\n");
1706  add_author(book, MSGTYPE_ALCHEMY);
1707  return;
1708  }
1709  op_name = at->clone.name;
1710 
1711  /* item name */
1712  if (strcmp(formula->title, "NONE")) {
1713  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "The %s of %s", op_name, formula->title);
1714  /* This results in things like pile of philo. sulfur.
1715  * while philo. sulfur may look better, without this,
1716  * you get things like 'the wise' because its missing the
1717  * water of section.
1718  */
1719  snprintf(title, sizeof(title), "%s: %s of %s", formula_book_name[RANDOM()%arraysize(formula_book_name)], op_name, formula->title);
1720  } else {
1721  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "The %s", op_name);
1722  snprintf(title, sizeof(title), "%s: %s", formula_book_name[RANDOM()%arraysize(formula_book_name)], op_name);
1723  if (at->clone.title) {
1724  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), " %s", at->clone.title);
1725  snprintf(title+strlen(title), sizeof(title)-strlen(title), " %s", at->clone.title);
1726  }
1727  }
1728  /* Lets name the book something meaningful ! */
1729  if (book->name)
1730  free_string(book->name);
1731  book->name = add_string(title);
1732  if (book->title) {
1733  free_string(book->title);
1734  book->title = NULL;
1735  }
1736 
1737  /* ingredients to make it */
1738  if (formula->ingred != NULL) {
1739  linked_char *next;
1740  archetype *at;
1741  char name[MAX_BUF];
1742 
1743  at = find_archetype(formula->cauldron);
1744  if (at)
1745  query_name(&at->clone, name, MAX_BUF);
1746  else
1747  snprintf(name, sizeof(name), "an unknown place");
1748 
1749  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf),
1750  " may be made at %s using the following ingredients:\n", name);
1751 
1752  for (next = formula->ingred; next != NULL; next = next->next) {
1753  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "%s\n", next->name);
1754  }
1755  } else
1756  LOG(llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, formula->title);
1757  if (retbuf[strlen(retbuf)-1] != '\n')
1758  snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "\n");
1759  if (book->msg)
1760  free_string(book->msg);
1761  book->msg = add_string(retbuf);
1762 }
1763 
1774 static char *msgfile_msg(int level, size_t booksize) {
1775  static char retbuf[BOOK_BUF];
1776  int i, msgnum;
1777  linked_char *msg = NULL;
1778 
1779  /* get a random message for the 'book' from linked list */
1780  if (nrofmsg > 1) {
1781  msg = first_msg;
1782  msgnum = RANDOM()%nrofmsg;
1783  for (i = 0; msg && i < nrofmsg && i != msgnum; i++)
1784  msg = msg->next;
1785  }
1786 
1787  if (msg && !book_overflow(retbuf, msg->name, booksize))
1788  snprintf(retbuf, sizeof(retbuf), "%s", msg->name);
1789  else
1790  snprintf(retbuf, sizeof(retbuf), "\n <undecipherable text>");
1791 
1792 #ifdef BOOK_MSG_DEBUG
1793  LOG(llevDebug, "\n info_list_msg() created strng: %d\n", strlen(retbuf));
1794  LOG(llevDebug, " MADE THIS:\n%s\n", retbuf);
1795 #endif
1796 
1797  return retbuf;
1798 }
1799 
1813 static char *god_info_msg(int level, char *retbuf, size_t booksize) {
1814  const char *name;
1815  char buf[BOOK_BUF];
1816  int i;
1817  size_t retlen, buflen;
1818  size_t introlen;
1819  const object *god = pntr_to_god_obj(get_rand_god());
1820  char en[BOOK_BUF];
1821 
1822  if (booksize > BOOK_BUF) {
1823  LOG(llevError, "common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (unsigned long)booksize, BOOK_BUF);
1824  booksize = BOOK_BUF;
1825  }
1826 
1827  if (!god)
1828  return (char *)NULL; /* oops, problems... */
1829  name = god->name;
1830 
1831  /* preamble.. */
1832  snprintf(retbuf, BOOK_BUF, "This document contains knowledge concerning the diety %s", name);
1833 
1834  retlen = strlen(retbuf);
1835 
1836  /* Always have as default information the god's descriptive terms. */
1837  if (nstrtok(god->msg, ",") > 0) {
1838  safe_strcat(retbuf, ", known as", &retlen, BOOK_BUF);
1839  safe_strcat(retbuf, strtoktolin(god->msg, ",", buf, sizeof(buf)), &retlen, BOOK_BUF);
1840  } else
1841  safe_strcat(retbuf, "...", &retlen, BOOK_BUF);
1842 
1843  safe_strcat(retbuf, "\n ---\n", &retlen, BOOK_BUF);
1844 
1845  introlen = retlen; /* so we will know if no new info is added later */
1846 
1847  /* Information about the god is random, and based on the level of the
1848  * 'book'. This goes through this loop 'level' times, reducing level by
1849  * 1 each time. If the info provided is filled up, we exit the loop.
1850  * otherwise, buf is appended to the existing book buffer.
1851  */
1852 
1853  while (level > 0) {
1854  buf[0]=' ';
1855  buf[1]='\0';
1856  if (level == 2 && RANDOM()%2) {
1857  /* enemy god */
1858 
1859  if (god->title)
1860  snprintf(buf, BOOK_BUF, "The gods %s and %s are enemies.\n ---\n", name, god->title);
1861  }
1862  if (level == 3 && RANDOM()%2) {
1863  /* enemy race, what the god's holy word effects */
1864  const char *enemy = god->slaying;
1865 
1866  if (enemy && !(god->path_denied&PATH_TURNING)
1867  && (i = nstrtok(enemy, ",")) > 0) {
1868  char tmpbuf[MAX_BUF];
1869 
1870  snprintf(buf, BOOK_BUF, "The holy words of %s have the power to slay creatures belonging to the ", name);
1871  if (i > 1)
1872  snprintf(tmpbuf, MAX_BUF, "following races:%s\n ---\n", strtoktolin(enemy, ",", en, sizeof(en)));
1873  else
1874  snprintf(tmpbuf, MAX_BUF, "race of%s\n ---\n", strtoktolin(enemy, ",", en, sizeof(en)));
1875 
1876  buflen = strlen(buf);
1877  safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
1878  }
1879  }
1880  if (level == 4 && RANDOM()%2) {
1881  /* Priest of god gets these protect,vulnerable... */
1882 
1883  char cp[BOOK_BUF];
1884  describe_resistance(god, 1, cp, BOOK_BUF);
1885 
1886  if (*cp) { /* This god does have protections */
1887  snprintf(buf, BOOK_BUF, "%s has a potent aura which is extended to faithful priests. The effects of this aura include:\n%s\n ---\n", name, cp);
1888  }
1889  }
1890  if (level == 5 && RANDOM()%2) {
1891  /* aligned race, summoning */
1892  const char *race = god->race; /* aligned race */
1893 
1894  if (race && !(god->path_denied&PATH_SUMMON)) {
1895  i = nstrtok(race, ",");
1896  if (i > 0) {
1897  char tmpbuf[MAX_BUF];
1898 
1899  snprintf(buf, BOOK_BUF, "Creatures sacred to %s include the\n", name);
1900 
1901  if (i > 1)
1902  snprintf(tmpbuf, MAX_BUF, "following races:%s\n ---\n", strtoktolin(race, ",", en, sizeof(en)));
1903  else
1904  snprintf(tmpbuf, MAX_BUF, "race of %s\n ---\n", strtoktolin(race, ",", en, sizeof(en)));
1905 
1906  buflen = strlen(buf);
1907  safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
1908  }
1909  }
1910  }
1911  if (level == 6 && RANDOM()%2) {
1912  /* blessing,curse properties of the god */
1913 
1914  char cp[MAX_BUF];
1915  describe_resistance(god, 1, cp, MAX_BUF);
1916 
1917  if (*cp) { /* This god does have protections */
1918  snprintf(buf, MAX_BUF, "\nThe priests of %s are known to be able to bestow a blessing which makes the recipient %s\n ---\n", name, cp);
1919  }
1920  }
1921  if (level == 8 && RANDOM()%2) {
1922  /* immunity, holy possession */
1923  int has_effect = 0, tmpvar;
1924  char tmpbuf[MAX_BUF];
1925 
1926  snprintf(buf, MAX_BUF, "\nThe priests of %s are known to make cast a mighty prayer of possession which gives the recipient", name);
1927 
1928  for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) {
1929  if (god->resist[tmpvar] == 100) {
1930  has_effect = 1;
1931  snprintf(tmpbuf, MAX_BUF, "Immunity to %s", attacktype_desc[tmpvar]);
1932  }
1933  }
1934  if (has_effect) {
1935  buflen = strlen(buf);
1936  safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
1937  safe_strcat(buf, "\n ---\n", &buflen, BOOK_BUF);
1938  } else {
1939  buf[0]=' ';
1940  buf[1]='\0';
1941  }
1942  }
1943  if (level == 12 && RANDOM()%2) {
1944  /* spell paths */
1945  int has_effect = 0;
1946 
1947  snprintf(buf, MAX_BUF, "It is rarely known fact that the priests of %s are mystically transformed. Effects of this include:\n", name);
1948  buflen = strlen(buf);
1949 
1950  if (god->path_attuned) {
1951  has_effect = 1;
1952  DESCRIBE_PATH_SAFE(buf, god->path_attuned, "Attuned", &buflen, BOOK_BUF);
1953  }
1954  if (god->path_repelled) {
1955  has_effect = 1;
1956  DESCRIBE_PATH_SAFE(buf, god->path_repelled, "Repelled", &buflen, BOOK_BUF);
1957  }
1958  if (god->path_denied) {
1959  has_effect = 1;
1960  DESCRIBE_PATH_SAFE(buf, god->path_denied, "Denied", &buflen, BOOK_BUF);
1961  }
1962  if (has_effect) {
1963  safe_strcat(buf, "\n ---\n", &buflen, BOOK_BUF);
1964  } else {
1965  buf[0]=' ';
1966  buf[1]='\0';
1967  }
1968  }
1969 
1970  /* check to be sure new buffer size dont exceed either
1971  * the maximum buffer size, or the 'natural' size of the
1972  * book...
1973  */
1974  if (book_overflow(retbuf, buf, booksize))
1975  break;
1976  if (strlen(buf) > 1)
1977  safe_strcat(retbuf, buf, &retlen, BOOK_BUF);
1978 
1979  level--;
1980  }
1981  if (retlen == introlen) {
1982  /* we got no information beyond the preamble! */
1983  safe_strcat(retbuf, " Unfortunately the rest of the information is hopelessly garbled!\n ---\n", &retlen, BOOK_BUF);
1984  }
1985 #ifdef BOOK_MSG_DEBUG
1986  LOG(llevDebug, "\n god_info_msg() created strng: %d\n", strlen(retbuf));
1987  fprintf(logfile, " MADE THIS:\n%s", retbuf);
1988 #endif
1989  return retbuf;
1990 }
1991 
2010 void tailor_readable_ob(object *book, int msg_type) {
2011  char msgbuf[BOOK_BUF];
2012  int level = book->level ? RANDOM()%book->level+1 : 1;
2013  size_t book_buf_size;
2014 
2015  /* safety */
2016  if (book->type != BOOK)
2017  return;
2018 
2019  if (level <= 0)
2020  return; /* if no level no point in doing any more... */
2021 
2022  /* Max text length this book can have. */
2023  book_buf_size = BOOKSIZE(book);
2024  book_buf_size -= strlen("\n"); /* Keep enough for final \n. */
2025 
2026  /* &&& The message switch &&& */
2027  /* Below all of the possible types of messages in the "book"s.
2028  */
2029  /*
2030  * IF you add a new type of book msg, you will have to do several things.
2031  * 1) make sure there is an entry in the msg switch below!
2032  * 2) make sure there is an entry in max_titles[] array.
2033  * 3) make sure there are entries for your case in new_text_title()
2034  * and add_authour().
2035  * 4) you may want separate authour/book name arrays in read.h
2036  */
2037 
2038  msg_type = msg_type > 0 ? msg_type : RANDOM()%6;
2039  switch (msg_type) {
2040  case MSGTYPE_MONSTER:
2041  mon_info_msg(level, msgbuf, book_buf_size);
2042  break;
2043 
2044  case MSGTYPE_ARTIFACT:
2045  artifact_msg(level, msgbuf, book_buf_size);
2046  break;
2047 
2048  case MSGTYPE_SPELLPATH: /* grouping incantations/prayers by path */
2049  spellpath_msg(level, msgbuf, book_buf_size);
2050  break;
2051 
2052  case MSGTYPE_ALCHEMY: /* describe an alchemy formula */
2053  make_formula_book(book, level);
2054  /* make_formula_book already gives title */
2055  return;
2056  break;
2057 
2058  case MSGTYPE_GODS: /* bits of information about a god */
2059  god_info_msg(level, msgbuf, book_buf_size);
2060  break;
2061 
2062  case MSGTYPE_LIB: /* use info list in lib/ */
2063  default:
2064  strcpy(msgbuf, msgfile_msg(level, book_buf_size));
2065  break;
2066  }
2067 
2068  strcat(msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
2069  if (strlen(msgbuf) > strlen("\n")) {
2070  if (book->msg)
2071  free_string(book->msg);
2072  book->msg = add_string(msgbuf);
2073  /* lets give the "book" a new name, which may be a compound word */
2074  change_book(book, msg_type);
2075  }
2076 }
2077 
2078 /*****************************************************************************
2079  *
2080  * Cleanup routine for readable stuff.
2081  *
2082  *****************************************************************************/
2083 
2084 void free_all_readable(void) {
2085  titlelist *tlist, *tnext;
2086  title *title1, *titlenext;
2087  linked_char *lmsg, *nextmsg;
2088  objectlink *monlink, *nextmon;
2089 
2090  LOG(llevDebug, "freeing all book information\n");
2091 
2092  for (tlist = booklist; tlist != NULL; tlist = tnext) {
2093  tnext = tlist->next;
2094  for (title1 = tlist->first_book; title1; title1 = titlenext) {
2095  titlenext = title1->next;
2096  if (title1->name)
2097  free_string(title1->name);
2098  if (title1->authour)
2099  free_string(title1->authour);
2100  if (title1->archname)
2101  free_string(title1->archname);
2102  free(title1);
2103  }
2104  free(tlist);
2105  }
2106  for (lmsg = first_msg; lmsg; lmsg = nextmsg) {
2107  nextmsg = lmsg->next;
2108  if (lmsg->name)
2109  free_string(lmsg->name);
2110  free(lmsg);
2111  }
2112  for (monlink = first_mon_info; monlink; monlink = nextmon) {
2113  nextmon = monlink->next;
2114  free(monlink);
2115  }
2116 }
2117 
2118 /*****************************************************************************
2119  *
2120  * Writeback routine for updating the bookarchive.
2121  *
2122  ****************************************************************************/
2123 
2128  FILE *fp;
2129  int index;
2130  char fname[MAX_BUF];
2131  title *book;
2132  titlelist *bl;
2133 
2134  /* If nothing changed, don't write anything */
2136  return;
2137 
2138  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
2139  LOG(llevDebug, "Updating book archive: %s...\n", fname);
2140 
2141  fp = fopen(fname, "w");
2142  if (fp == NULL) {
2143  LOG(llevDebug, "Can't open book archive file %s\n", fname);
2144  return;
2145  }
2146 
2147  for (bl = get_titlelist(0), index = 0; bl; bl = bl->next, index++) {
2148  for (book = bl->first_book; book; book = book->next)
2149  if (book && book->authour) {
2150  fprintf(fp, "title %s\n", book->name);
2151  fprintf(fp, "authour %s\n", book->authour);
2152  fprintf(fp, "arch %s\n", book->archname);
2153  fprintf(fp, "level %d\n", book->level);
2154  fprintf(fp, "type %d\n", index);
2155  /* C89 doesn't have %zu... */
2156  fprintf(fp, "size %lu\n", (unsigned long)book->size);
2157  fprintf(fp, "index %d\n", book->msg_index);
2158  fprintf(fp, "end\n");
2159  }
2160  }
2161  if (ferror(fp)) {
2162  LOG(llevError, "Error during book archive save.\n");
2163  fclose(fp);
2164  return;
2165  }
2166  if (fclose(fp) != 0) {
2167  LOG(llevError, "Error during book archive save.\n");
2168  return;
2169  }
2170  chmod(fname, SAVE_MODE);
2172 }
2173 
2182  uint8 subtype = readable->subtype;
2183 
2184  if (subtype > last_readable_subtype)
2185  return &readable_message_types[0];
2186  return &readable_message_types[subtype];
2187 }
EXTERN FILE * logfile
Definition: global.h:220
#define MSG_TYPE_PAPER
Definition: newclient.h:319
const char * title
Definition: recipe.h:11
static const char *const heavy_book_name[]
Definition: readable.c:381
#define FOOD
Definition: define.h:118
#define RING
Definition: define.h:232
archetype * find_archetype(const char *name)
Definition: arch.c:700
#define OUT_OF_MEMORY
Definition: define.h:94
static char * msgfile_msg(int level, size_t booksize)
Definition: readable.c:1774
#define PATH_MISSILE
Definition: spells.h:45
static char * strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size)
Definition: readable.c:666
#define MSGTYPE_ARTIFACT
Definition: readable.c:86
#define MSG_TYPE_PAPER_LETTER_OLD_1
Definition: newclient.h:372
Definition: object.h:298
#define MSG_TYPE_CARD_STRANGE_2
Definition: newclient.h:362
const char * race
Definition: object.h:171
static void init_msgfile(void)
Definition: readable.c:714
#define MSG_TYPE_MONUMENT_STONE_2
Definition: newclient.h:392
#define PATH_MIND
Definition: spells.h:51
#define MSG_TYPE_SIGN_DIR_LEFT
Definition: newclient.h:386
#define SET_FLAG(xyz, p)
Definition: define.h:510
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
Definition: newclient.h:398
static void make_formula_book(object *book, int level)
Definition: readable.c:1656
static titlelist * get_titlelist(int i)
Definition: readable.c:605
static void add_book_to_list(const object *book, int msgtype)
Definition: readable.c:1144
#define MSG_TYPE_BOOK_CLASP_1
Definition: newclient.h:342
#define PATH_TURNING
Definition: spells.h:57
const char * archname
Definition: readable.c:107
#define MSG_TYPE_MONUMENT_STATUE_1
Definition: newclient.h:394
object * get_random_mon(int level)
Definition: readable.c:1316
#define MSG_TYPE_CARD
Definition: newclient.h:318
#define PATH_LIGHT
Definition: spells.h:60
#define MSG_TYPE_BOOK_QUARTO_2
Definition: newclient.h:347
struct artifactstruct * items
Definition: artifact.h:52
object * mon
Definition: comet_perf.c:74
static const arttypename art_name_array[]
Definition: readable.c:214
void free_string(sstring str)
Definition: shstr.c:272
#define HUGE_BUF
Definition: define.h:83
#define MSGTYPE_MONSTER
Definition: readable.c:85
static char * artifact_msg(int level, char *retbuf, size_t booksize)
Definition: readable.c:1477
object clone
Definition: object.h:326
linked_char * ingred
Definition: recipe.h:22
static const int last_readable_subtype
Definition: readable.c:533
static const char *const path_book_name[]
Definition: readable.c:182
#define MSG_TYPE_PAPER_LETTER_OLD_2
Definition: newclient.h:373
static void init_book_archive(void)
Definition: readable.c:784
#define MSG_TYPE_CARD_STRANGE_1
Definition: newclient.h:361
const char * slaying
Definition: object.h:172
#define MSG_TYPE_SIGN
Definition: newclient.h:320
#define PATH_RESTORE
Definition: spells.h:49
#define MSG_TYPE_BOOK_SPELL_EVOKER
Definition: newclient.h:348
int msg_index
Definition: readable.c:110
uint8 subtype
Definition: object.h:190
#define MSG_TYPE_CARD_MONEY_3
Definition: newclient.h:366
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
Definition: newclient.h:399
#define MSG_TYPE_CARD_ELEGANT_2
Definition: newclient.h:359
#define PATH_FIRE
Definition: spells.h:42
const char * name
Definition: readable.c:105
void close_and_delete(FILE *fp, int compressed)
Definition: porting.c:748
static void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: define.h:924
#define BOOTS
Definition: define.h:281
static title * find_title(const object *book, int msgtype)
Definition: readable.c:984
#define CLOAK
Definition: define.h:268
#define GIRDLE
Definition: define.h:295
uint32 path_attuned
Definition: object.h:194
#define MSGTYPE_ALCHEMY
Definition: readable.c:88
sint16 sp
Definition: living.h:83
static object * get_next_mon(const object *tmp)
Definition: readable.c:1400
uint32 path_repelled
Definition: object.h:195
#define ARMOUR
Definition: define.h:128
tag_t id
Definition: object.h:301
Definition: object.h:321
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:126
struct titlestruct title
#define MSG_TYPE_SIGN_DIR_RIGHT
Definition: newclient.h:387
object * ob
Definition: object.h:299
#define MSG_TYPE_BOOK_SPELL_PRAYER
Definition: newclient.h:349
void add_abilities(object *op, object *change)
Definition: treasure.c:1653
#define MSG_TYPE_MONUMENT_STATUE_2
Definition: newclient.h:395
#define AMULET
Definition: define.h:153
static char * spellpath_msg(int level, char *retbuf, size_t booksize)
Definition: readable.c:1607
int chance
Definition: recipe.h:14
const char * title
Definition: object.h:170
#define PATH_ELEC
Definition: spells.h:44
#define MSG_TYPE_BOOK
Definition: newclient.h:317
static const char *const mon_book_name[]
Definition: readable.c:262
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
Definition: shstr.c:393
void describe_resistance(const object *op, int newline, char *buf, size_t size)
Definition: item.c:399
struct titlestruct * next
Definition: readable.c:111
const char * name
Definition: readable.c:122
struct titleliststruct titlelist
uint32 path_denied
Definition: object.h:196
#define MSG_TYPE_PAPER_LETTER_NEW_1
Definition: newclient.h:374
#define MSG_TYPE_PAPER_SCROLL_MAGIC
Definition: newclient.h:382
object * create_archetype(const char *name)
Definition: arch.c:625
artifactlist * find_artifactlist(int type)
Definition: treasure.c:1431
char ** arch_name
Definition: recipe.h:13
#define MSG_TYPE_PAPER_SCROLL_NEW_1
Definition: newclient.h:380
int total_chance
Definition: recipe.h:31
#define MSG_TYPE_BOOK_SPELL_SORCERER
Definition: newclient.h:351
sint32 weight
Definition: object.h:216
#define FLAG_UNAGGRESSIVE
Definition: define.h:568
struct namebytype arttypename
#define FLAG_CHANGING
Definition: define.h:559
#define BOOK_BUF
Definition: book.h:39
#define HORN
Definition: define.h:147
static const uint32 spellpathdef[NRSPELLPATHS]
Definition: readable.c:158
struct linked_char * next
Definition: global.h:161
#define FLAG_IDENTIFIED
Definition: define.h:557
#define PATH_TRANSMUTE
Definition: spells.h:55
#define MSG_TYPE_PAPER_SCROLL_NEW_2
Definition: newclient.h:381
uint16 chance
Definition: artifact.h:39
int strtoint(const char *buf)
Definition: recipe.c:616
godlink * get_rand_god(void)
Definition: holy.c:111
static int need_to_write_bookarchive
Definition: readable.c:141
#define PATH_DEATH
Definition: spells.h:59
const char * name
Definition: object.h:167
#define SPELL
Definition: define.h:283
linked_char * allowed
Definition: artifact.h:42
struct titleliststruct * next
Definition: readable.c:117
#define MSG_TYPE_CARD_SIMPLE_1
Definition: newclient.h:355
#define MSG_TYPE_PAPER_NOTE_3
Definition: newclient.h:371
void fatal(int err)
Definition: glue.c:60
#define MSG_TYPE_SIGN_DIR_BOTH
Definition: newclient.h:388
#define MSG_TYPE_CARD_SIMPLE_2
Definition: newclient.h:356
void tailor_readable_ob(object *book, int msg_type)
Definition: readable.c:2010
#define PATH_PROT
Definition: spells.h:41
static int nrofmsg
Definition: readable.c:147
unsigned char uint8
Definition: global.h:75
const object * pntr_to_god_obj(godlink *godlnk)
Definition: holy.c:133
static const char *const book_author[]
Definition: readable.c:394
#define MSG_TYPE_MONUMENT_STONE_1
Definition: newclient.h:391
#define WEAPON
Definition: define.h:127
#define arraysize(arrayname)
Definition: readable.c:97
uint16 total_chance
Definition: artifact.h:50
static const char *const gods_author[]
Definition: readable.c:312
#define PATH_SELF
Definition: spells.h:46
static int nrofmon
Definition: readable.c:141
static titlelist * booklist
Definition: readable.c:132
static void add_book(title *book, int type, const char *fname, int lineno)
Definition: readable.c:902
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
EXTERN const char *const attacktype_desc[NROFATTACKS]
Definition: attack.h:165
void init_readable(void)
Definition: readable.c:952
static void add_author(object *op, int msgtype)
Definition: readable.c:1072
#define MAX_BUF
Definition: define.h:81
#define NRSPELLPATHS
Definition: spells.h:68
#define GLOVES
Definition: define.h:282
#define MSG_TYPE_PAPER_SCROLL_OLD_1
Definition: newclient.h:378
object * get_object(void)
Definition: object.c:921
#define MSG_TYPE_SIGN_BASIC
Definition: newclient.h:385
#define MSG_TYPE_CARD_STRANGE_3
Definition: newclient.h:363
#define MSGTYPE_SPELLPATH
Definition: readable.c:87
#define MSG_TYPE_PAPER_LETTER_NEW_2
Definition: newclient.h:375
#define BOOK
Definition: define.h:120
#define BRACERS
Definition: define.h:286
static const char *const mon_author[]
Definition: readable.c:279
#define PATH_CREATE
Definition: spells.h:52
#define BOOKSIZE(xyz)
Definition: book.h:54
static int unique_book(const object *book, int msgtype)
Definition: readable.c:1120
#define MSG_TYPE_MONUMENT_STONE_3
Definition: newclient.h:393
sint16 resist[NROFATTACKS]
Definition: object.h:192
#define MSG_TYPE_MONUMENT_WALL_1
Definition: newclient.h:400
static const char *const gods_book_name[]
Definition: readable.c:298
#define MSG_TYPE_PAPER_ENVELOPE_2
Definition: newclient.h:377
#define DESCRIBE_PATH_SAFE(retbuf, variable, name, len, maxlen)
Definition: define.h:986
#define MSG_TYPE_MONUMENT_WALL_2
Definition: newclient.h:401
const char * datadir
Definition: global.h:334
const char * cauldron
Definition: recipe.h:26
#define SHIELD
Definition: define.h:145
#define MSG_TYPE_BOOK_SPELL_PYRO
Definition: newclient.h:350
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
const char * authour
Definition: readable.c:106
const char * name
Definition: global.h:160
#define PATH_INFO
Definition: spells.h:54
#define PATH_FROST
Definition: spells.h:43
static const char *const art_author[]
Definition: readable.c:249
static titlelist * get_empty_booklist(void)
Definition: readable.c:560
static const readable_message_type readable_message_types[]
Definition: readable.c:467
sint16 grace
Definition: living.h:85
#define MSG_TYPE_BOOK_CLASP_2
Definition: newclient.h:343
#define PATH_TRANSFER
Definition: spells.h:56
const char * localdir
Definition: global.h:335
living stats
Definition: object.h:219
static const char *const formula_author[]
Definition: readable.c:342
struct archt * arch
Definition: object.h:263
const char * skill
Definition: recipe.h:25
int type
Definition: readable.c:123
struct oblnk * next
Definition: object.h:300
size_t arch_names
Definition: recipe.h:12
#define SKILL
Definition: define.h:157
#define PATH_ABJURE
Definition: spells.h:48
struct Settings settings
Definition: init.c:48
static char * god_info_msg(int level, char *retbuf, size_t booksize)
Definition: readable.c:1813
#define MSG_TYPE_BOOK_ELEGANT_1
Definition: newclient.h:344
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
Definition: readable.c:696
struct archt * next
Definition: object.h:323
#define MSGTYPE_MSGFILE
Definition: readable.c:90
#define SAVE_MODE
Definition: config.h:634
#define NROFATTACKS
Definition: attack.h:45
void free_all_readable(void)
Definition: readable.c:2084
struct recipestruct * next
Definition: recipe.h:23
static const int max_titles[6]
Definition: readable.c:536
static const char *const path_author[]
Definition: readable.c:191
const char * msg
Definition: object.h:175
void write_book_archive(void)
Definition: readable.c:2127
static const char *const light_book_name[]
Definition: readable.c:364
#define MSG_TYPE_CARD_SIMPLE_3
Definition: newclient.h:357
#define MSG_TYPE_BOOK_QUARTO_1
Definition: newclient.h:346
void describe_item(const object *op, const object *owner, char *retbuf, size_t size)
Definition: item.c:1018
#define BOW
Definition: define.h:126
static objectlink * first_mon_info
Definition: readable.c:135
sstring add_string(const char *str)
Definition: shstr.c:116
struct titlestruct * first_book
Definition: readable.c:116
static linked_char * first_msg
Definition: readable.c:153
static void change_book(object *book, int msgtype)
Definition: readable.c:1186
#define FLAG_MONSTER
Definition: define.h:541
static void init_mon_info(void)
Definition: readable.c:920
const readable_message_type * get_readable_message_type(object *readable)
Definition: readable.c:2181
#define HELMET
Definition: define.h:146
#define MSG_TYPE_PAPER_NOTE_2
Definition: newclient.h:370
#define MSG_TYPE_CARD_ELEGANT_3
Definition: newclient.h:360
#define MSG_TYPE_MONUMENT_WALL_3
Definition: newclient.h:402
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define MSG_TYPE_CARD_MONEY_2
Definition: newclient.h:365
#define MSG_TYPE_BOOK_ELEGANT_2
Definition: newclient.h:345
#define MSG_TYPE_PAPER_SCROLL_OLD_2
Definition: newclient.h:379
#define MSG_TYPE_MONUMENT_STATUE_3
Definition: newclient.h:396
#define MSGTYPE_LIB
Definition: readable.c:84
#define ARROW
Definition: define.h:125
unsigned int uint32
Definition: global.h:58
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
Definition: newclient.h:397
#define MSG_TYPE_MONUMENT
Definition: newclient.h:321
#define MSG_TYPE_PAPER_NOTE_1
Definition: newclient.h:369
static const char *const formula_book_name[]
Definition: readable.c:330
static char * mon_info_msg(int level, char *buf, size_t booksize)
Definition: readable.c:1429
void copy_object(object *op2, object *op)
Definition: object.c:758
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
object * item
Definition: artifact.h:38
#define PATH_DETONATE
Definition: spells.h:50
void free_object(object *ob)
Definition: object.c:1238
static int nstrtok(const char *buf1, const char *buf2)
Definition: readable.c:636
static char * mon_desc(const object *mon, char *buf, size_t size)
Definition: readable.c:1383
static const char *const book_descrpt[]
Definition: readable.c:440
#define MSGTYPE_GODS
Definition: readable.c:89
static void new_text_name(object *book, int msgtype)
Definition: readable.c:1023
static const char *const art_book_name[]
Definition: readable.c:234
size_t size
Definition: readable.c:109
sint16 level
Definition: object.h:202
#define MSG_TYPE_BOOK_SPELL_SUMMONER
Definition: newclient.h:352
EXTERN archetype * first_archetype
Definition: global.h:195
FILE * open_and_uncompress(const char *name, int flag, int *compressed)
Definition: porting.c:724
sint32 value
Definition: object.h:201
const char * name
Definition: object.h:322
#define PATH_WOUNDING
Definition: spells.h:58
#define MSG_TYPE_CARD_MONEY_1
Definition: newclient.h:364
struct recipestruct * items
Definition: recipe.h:33
recipelist * get_formulalist(int i)
Definition: recipe.c:112
#define MSG_TYPE_PAPER_ENVELOPE_1
Definition: newclient.h:376
uint8 type
Definition: object.h:189
struct artifactstruct * next
Definition: artifact.h:41
#define PATH_TELE
Definition: spells.h:53
#define MSG_TYPE_CARD_ELEGANT_1
Definition: newclient.h:358
#define MAX_TITLE_CHECK
Definition: readable.c:82
#define PATH_SUMMON
Definition: spells.h:47
static title * get_empty_book(void)
Definition: readable.c:580