Crossfire Server, Trunk
readable.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
23 /* laid down initial file - dec 1995. -b.t. thomas@astro.psu.edu */
24 
25 #include "global.h"
26 
27 #include <assert.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 
33 #include "book.h"
34 #include "living.h"
35 #include "output_file.h"
36 #include "spells.h"
37 #include "assets.h"
38 #include "AssetsManager.h"
39 
40 /* Define this if you want to archive book titles by contents.
41  * This option should enforce UNIQUE combinations of titles,authors and
42  * msg contents during and *between *game sessions.
43  * Note: a slight degeneracy exists since books are archived based on an integer
44  * index value calculated from the message text (similar to alchemy formulae).
45  * Sometimes two widely different messages have the same index value (rare). In
46  * this case, it is possible to occasionally generate 2 books with same title and
47  * different message content. Not really a bug, but rather a feature. This action
48  * should keeps player on their toes ;).
49  * Also, note that there is *finite *space available for archiving message and titles.
50  * Once this space is used, books will stop being archived. Not a serious problem
51  * under the current regime, since there are generally fewer possible (random)
52  * messages than space available on the titlelists.
53  * One exception (for sure) are the monster messages. But no worries, you should
54  * see all of the monster info in some order (but not all possble combinations)
55  * before the monster titlelist space is run out. You can increase titlelist
56  * space by increasing the array sizes for the monster book_authours and book_names
57  * (see max_titles[] array and include/read.h). Since the unique_book algorthm is
58  * kinda stupid, this program *may *slow down program execution if defined (but I don't
59  * think its a significant problem, at least, I have no problems running this option
60  * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg
61  * combinations have been generated, unique_book isnt called anymore. It takes 5-10
62  * sessions for this to happen).
63  * Final note: the game remembers book/title/msg combinations from reading the
64  * file lib/bookarch. If you REMOVE this file, you will lose your archive. So
65  * be sure to copy it over to the new lib directory when you change versions.
66  * -b.t.
67  */
68 
69 /* This flag is useful to see what kind of output messages are created */
70 /* #define BOOK_MSG_DEBUG */
71 
72 /* This flag is useful for debugging archiving action */
73 /* #define ARCHIVE_DEBUG */
74 
76 #define MAX_TITLE_CHECK 20
77 
79 #define MSGTYPE_LIB 0
80 
81 #define MSGTYPE_MONSTER 1
82 
83 #define MSGTYPE_ARTIFACT 2
84 
85 #define MSGTYPE_SPELLPATH 3
86 
87 #define MSGTYPE_ALCHEMY 4
88 
89 #define MSGTYPE_GODS 5
90 
91 #define MSGTYPE_MSGFILE 6
92 
98 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
99 
100 /* Moved these structures from struct.h to this file in 0.94.3 - they
101  * are not needed anyplace else, so why have them globally declared?
102  */
103 
108 struct title {
109  const char *name;
110  const char *authour;
111  const char *archname;
112  unsigned int level;
113  size_t size;
114  int msg_index;
116 };
117 
121 struct titlelist {
122  int number;
125 };
126 
128 struct arttypename {
129  const char *name;
130  int type;
131 };
132 
133 static void add_book(title *book, int type, const char *fname, int lineno);
134 
139 static titlelist *booklist = NULL;
140 
142 static std::vector<object *> monsters;
143 
149 static const uint32_t spellpathdef[NRSPELLPATHS] = {
150  PATH_PROT,
151  PATH_FIRE,
152  PATH_FROST,
153  PATH_ELEC,
154  PATH_MISSILE,
155  PATH_SELF,
156  PATH_SUMMON,
157  PATH_ABJURE,
158  PATH_RESTORE,
160  PATH_MIND,
161  PATH_CREATE,
162  PATH_TELE,
163  PATH_INFO,
166  PATH_TURNING,
168  PATH_DEATH,
169  PATH_LIGHT
170 };
171 
173 static const char *const path_book_name[] = {
174  "codex",
175  "compendium",
176  "documentary",
177  "exposition",
178  "tables",
179  "treatise"
180 };
181 
183 static const char *const path_author[] = {
184  "aether",
185  "arcana",
186  "astral byways",
187  "connections",
188  "the Grey Council",
189  "deep pathways",
190  "knowledge",
191  "magic",
192  "mystic ways",
193  "pathways",
194  "power",
195  "spells",
196  "transforms",
197  "the mystic veil",
198  "unknown spells"
199 };
200 
207 static const arttypename art_name_array[] = {
208  { "Helmet", HELMET },
209  { "Amulet", AMULET },
210  { "Shield", SHIELD },
211  { "Bracers", BRACERS },
212  { "Boots", BOOTS },
213  { "Cloak", CLOAK },
214  { "Gloves", GLOVES },
215  { "Gridle", GIRDLE },
216  { "Ring", RING },
217  { "Horn", ROD },
218  { "Missile Weapon", BOW },
219  { "Missile", ARROW },
220  { "Hand Weapon", WEAPON },
221  { "Artifact", SKILL },
222  { "Food", FOOD },
223  { "Body Armour", ARMOUR }
224 };
225 
227 static const char *const art_book_name[] = {
228  "assemblage",
229  "collection",
230  "file",
231  "files",
232  "guide",
233  "handbook",
234  "index",
235  "inventory",
236  "list",
237  "listing",
238  "omnibus",
239  "record",
240  "record book",
241  "trove"
242 };
243 
245 static const char *const art_author[] = {
246  "ancient things",
247  "artifacts",
248  "equipment",
249  "Havlor", /* ancient warrior scribe :) */
250  "hoards",
251  "items",
252  "lost artifacts",
253  "the ancients",
254  "treasures",
255  "useful things"
256 };
257 
261 static const char *const mon_book_name[] = {
262  "beastuary",
263  "catalog",
264  "compilation",
265  "collection",
266  "encyclopedia",
267  "field notes",
268  "guide",
269  "handbook",
270  "list",
271  "manual",
272  "notes",
273  "omnibus",
274  "record",
275  "reference",
276  "register",
277  "traveller's guide",
278  "volume"
279 };
280 
282 static const char *const mon_author[] = {
283  "beasts",
284  "beings",
285  "creatures",
286  "dezidens",
287  "dwellers",
288  "evil nature",
289  "life",
290  "monsters",
291  "nature",
292  "new life",
293  "residents",
294  "the spawn",
295  "the living",
296  "the wilds",
297  "things"
298 };
299 
303 static const char *const gods_book_name[] = {
304  "devotional",
305  "devout notes",
306  "divine text",
307  "divine work",
308  "holy book",
309  "holy record",
310  "hymnal",
311  "illuminated text",
312  "moral text",
313  "pious pamphlet",
314  "sacred guide",
315  "testament",
316  "transcript",
317 };
318 
320 static const char *const gods_author[] = {
321  "cults",
322  "dieties",
323  "joy",
324  "lasting curse",
325  "madness",
326  "religions",
327  "rituals",
328  "the dead",
329  "the gods",
330  "the heirophant",
331  "the poor priest",
332  "the priestess",
333  "pain",
334  "white",
335  "worship"
336 };
337 
341 static const char *const formula_book_name[] = {
342  "cookbook",
343  "formulary",
344  "lab book",
345  "lab notes",
346  "recipe book",
347  "experiment record",
348  "work plan",
349  "design notes",
350  "research notes",
351  "crafting manual"
352 };
353 
355 static const char *const formula_author[] = {
356  "Albertus Magnus",
357  "alchemy",
358  "balms",
359  "creation",
360  "dusts",
361  "magical manufacture",
362  "making",
363  "philosophical items",
364  "potions",
365  "powders",
366  "the cauldron",
367  "the lamp black",
368  "transmutation",
369  "waters"
370 };
371 
377 static const char *const light_book_name[] = {
378  "calendar",
379  "datebook",
380  "diary",
381  "essay",
382  "guidebook",
383  "handbook",
384  "ledger",
385  "notes",
386  "notebook",
387  "octavo",
388  "opuscule",
389  "pamphlet",
390  "practicum",
391  "script",
392  "transcript"
393 };
394 
396 static const char *const heavy_book_name[] = {
397  "catalog",
398  "compendium",
399  "dissertation",
400  "guide",
401  "manual",
402  "opus",
403  "tome",
404  "treatise",
405  "volume",
406  "work"
407 };
408 
410 static const char *const book_author[] = {
411  "Abdulah",
412  "Al'hezred",
413  "Alywn",
414  "Arundel",
415  "Arvind",
416  "Aerlingas",
417  "Bacon",
418  "Baliqendii",
419  "Bosworth",
420  "Beathis",
421  "Bertil",
422  "Cauchy",
423  "Chakrabarti",
424  "der Waalis",
425  "Dirk",
426  "Djwimii",
427  "Eisenstaadt",
428  "Fendris",
429  "Frank",
430  "Habbi",
431  "Harlod",
432  "Ichibod",
433  "Janus",
434  "June",
435  "Laplace",
436  "Magnuson",
437  "Nandii",
438  "Nitfeder",
439  "Norris",
440  "Parael",
441  "Penhew",
442  "Sophia",
443  "Skilly",
444  "Tahir",
445  "Thockmorton",
446  "Thomas",
447  "van Helsing",
448  "van Pelt",
449  "Voormis",
450  "Xavier",
451  "Xeno",
452  "Zardoz",
453  "Zagy"
454 };
455 
457 static const char *const book_descrpt[] = {
458  "ancient",
459  "cryptic",
460  "cryptical",
461  "dusty",
462  "hierarchical",
463  "grizzled",
464  "gold-gilt",
465  "great",
466  "lost",
467  "magnificent",
468  "musty",
469  "mythical",
470  "mystical",
471  "rustic",
472  "stained",
473  "silvered",
474  "transcendental",
475  "weathered"
476 };
477 
485  /*subtype 0 */ { 0, 0 },
486  /* book messages subtypes */
487  /*subtype 1 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1 },
496  /*subtype 10 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER },
498  /* card messages subtypes*/
507  /*subtype 20 */ { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3 },
511  /* Paper messages subtypes */
518  /*subtype 30 */ { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2 },
526  /* road signs messages subtypes */
529  /*subtype 40 */ { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT },
531  /* stones and monument messages */
545 };
546 
549 
551 static const int max_titles[6] = {
553  arraysize(mon_book_name)*arraysize(mon_author), /* MSGTYPE_MONSTER */
554  arraysize(art_book_name)*arraysize(art_author), /* MSGTYPE_ARTIFACT */
555  arraysize(path_book_name)*arraysize(path_author), /* MSGTYPE_SPELLPATH */
556  arraysize(formula_book_name)*arraysize(formula_author), /* MSGTYPE_ALCHEMY */
557  arraysize(gods_book_name)*arraysize(gods_author), /* MSGTYPE_GODS */
558 };
559 
560 /******************************************************************************
561  *
562  * Start of misc. readable functions used by others functions in this file
563  *
564  *****************************************************************************/
565 
576  titlelist *bl = (titlelist *)calloc(1, sizeof(titlelist));
577 
578  if (bl == NULL)
580  return bl;
581 }
582 
592 static title *get_empty_book(void) {
593  title *t = (title *)calloc(1, sizeof(title));
594 
595  if (t == NULL)
597  return t;
598 }
599 
610 static titlelist *get_titlelist(int i) {
611  titlelist *tl;
612  int number;
613 
614  if (i < 0 || i >= (int)arraysize(max_titles)) {
615  LOG(llevInfo, "Warning: invalid book index %d, using 0 instead\n", i);
616  return booklist;
617  }
618 
619  for (tl = booklist, number = i; tl && number; tl = tl->next, number--) {
620  if (!tl->next)
621  tl->next = get_empty_booklist();
622  }
623 
624  return tl;
625 }
626 
627 /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file
628  * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
629 
641 int nstrtok(const char *buf1, const char *buf2) {
642  char *tbuf, buf[MAX_BUF];
643  int number = 0;
644 
645  if (!buf1 || !buf2)
646  return 0;
647 
648  strlcpy(buf, buf1, sizeof(buf));
649  for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
650  number++;
651  }
652  return number;
653 }
654 
660 const char *trim(const char *buf) {
661  while ((*buf) == ' ') {
662  buf++;
663  }
664  return buf;
665 }
666 
683 char *strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size) {
684  int maxi, i = nstrtok(buf1, buf2);
685  char *tbuf, buf[MAX_BUF];
686 
687  maxi = i;
688  strlcpy(buf, buf1, sizeof(buf));
689  snprintf(retbuf, size, " ");
690  for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
691  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "%s", trim(tbuf));
692  i--;
693  if (i == 1 && maxi > 1)
694  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), " and ");
695  else if (i > 0 && maxi > 1)
696  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ", ");
697  else {
698  // Remove a trailing newline if it is there.
699  int end = strlen(retbuf);
700  if (retbuf[end-1] == '\n')
701  end--;
702  snprintf(retbuf+end, size-end, ".");
703  }
704  }
705  return retbuf;
706 }
707 
718 int book_overflow(const char *buf1, const char *buf2, size_t booksize) {
719  if (buf_overflow(buf1, buf2, BOOK_BUF-2) /* 2 less so always room for trailing \n */
720  || buf_overflow(buf1, buf2, booksize))
721  return 1;
722  return 0;
723 }
724 
725 /*****************************************************************************
726  *
727  * Start of initialization related functions.
728  *
729  ****************************************************************************/
730 
737 static void init_book_archive(void) {
738  FILE *fp;
739 #ifdef BOOK_MSG_DEBUG
740  int nroftitle = 0;
741 #endif
742  char buf[MAX_BUF], fname[MAX_BUF], *cp;
743  static int did_init_barch = 0;
744 
745  if (did_init_barch)
746  return;
747  did_init_barch = 1;
748 
749  if (!booklist)
751 
752  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
753  LOG(llevDebug, " Reading bookarch from %s...\n", fname);
754 
755  fp = fopen(fname, "r");
756  if (fp != NULL) {
757  int type;
758  size_t i;
759  titlelist *bl;
760  int lineno;
761  title *book;
762  int skipping;
763 
764  skipping = 0;
765  book = NULL;
766  type = -1;
767  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
768  int len;
769  int value;
770 
771  if (*buf == '#')
772  continue;
773  cp = strchr(buf, '\n');
774  if (cp != NULL) {
775  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
776  cp--;
777  *cp = '\0';
778  }
779  cp = buf;
780  if (strncmp(buf, "title ", 6) == 0) {
781  skipping = 0;
782  cp = buf+6;
783  while (*cp == ' ' || *cp == '\t')
784  cp++;
785  if (*cp == '\0') {
786  LOG(llevInfo, "Warning: missing book title at %s, line %d\n", fname, lineno);
787  book = NULL;
788  } else {
789  book = get_empty_book(); /* init new book entry */
790  book->name = add_string(cp);
791  type = -1;
792 #ifdef BOOK_MSG_DEBUG
793  nroftitle++;
794 #endif
795  }
796  } else if (book == NULL) {
797  if (!skipping) {
798  skipping = 1;
799  LOG(llevInfo, "Warning: expecting 'title' at %s, line %d\n", fname, lineno);
800  }
801  } else if (strncmp(buf, "authour ", 8) == 0) {
802  cp = buf+8;
803  while (*cp == ' ' || *cp == '\t')
804  cp++;
805  if (*cp == '\0') {
806  LOG(llevInfo, "Warning: missing book authour at %s, line %d\n", fname, lineno);
807  } else {
808  book->authour = add_string(cp);
809  }
810  } else if (strncmp(buf, "arch ", 5) == 0) {
811  cp = buf+5;
812  while (*cp == ' ' || *cp == '\t')
813  cp++;
814  if (*cp == '\0') {
815  LOG(llevInfo, "Warning: missing book arch at %s, line %d\n", fname, lineno);
816  } else {
817  book->archname = add_string(cp);
818  }
819  } else if (sscanf(buf, "level %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
820  book->level = value;
821  } else if (sscanf(buf, "type %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
822  type = value;
823  } else if (sscanf(buf, "size %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
824  book->size = value;
825  } else if (sscanf(buf, "index %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
826  book->msg_index = value;
827  } else if (strcmp(buf, "end") == 0) { /* link it */
828  add_book(book, type, fname, lineno);
829  book = NULL;
830  type = -1;
831  } else {
832  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
833  }
834  }
835  if (book != NULL) {
836  LOG(llevInfo, "Warning: missing 'end' at %s, line %d\n", fname, lineno);
837  add_book(book, type, fname, lineno);
838  }
839  LOG(llevDebug, " book archives(used/avail):\n");
840  for (bl = booklist, i = 0; bl != NULL && i < arraysize(max_titles); bl = bl->next, i++) {
841  LOG(llevDebug, "(%d/%d)\n", bl->number, max_titles[i]);
842  }
843  fclose(fp);
844  }
845 
846 #ifdef BOOK_MSG_DEBUG
847  LOG(llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle);
848 #endif
849  LOG(llevDebug, " done.\n");
850 }
851 
859 static void add_book(title *book, int type, const char *fname, int lineno) {
860  titlelist *bl;
861 
862  if (type == -1) {
863  LOG(llevInfo, "Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
864  type = 0;
865  }
866 
867  bl = get_titlelist(type);
868  book->next = bl->first_book;
869  bl->first_book = book;
870  bl->number++;
871 }
872 
873 static void do_monster(archetype *at) {
874  if (QUERY_FLAG(&at->clone, FLAG_MONSTER) && (!at->head)
877  monsters.push_back(&at->clone);
878  }
879 }
880 
885 static void init_mon_info(void) {
886  static int did_init_mon_info = 0;
887 
888  if (did_init_mon_info)
889  return;
890  did_init_mon_info = 1;
891 
893 
894  LOG(llevDebug, "init_mon_info() got %zu monsters\n", monsters.size());
895 }
896 
903 void init_readable(void) {
904  static int did_this = 0;
905 
906  if (did_this)
907  return;
908  did_this = 1;
909 
910  LOG(llevDebug, "Initializing reading data...\n");
912  init_mon_info();
913  LOG(llevDebug, " done reading data\n");
914 }
915 
916 /*****************************************************************************
917  *
918  * This is the start of the administrative functions when creating
919  * new books (ie, updating title and the like)
920  *
921  *****************************************************************************/
922 
934 static title *find_title(const object *book, int msgtype) {
935  title *t;
936  titlelist *tl;
937  size_t length;
938  int index;
939 
940  if (msgtype < 0)
941  return (title *)NULL;
942 
943  tl = get_titlelist(msgtype);
944  if (!tl)
945  return (title *)NULL;
946 
947  length = strlen(book->msg);
948  index = strtoint(book->msg);
949  for (t = tl->first_book; t; t = t->next)
950  if (t->size == length && t->msg_index == index) {
951 #ifdef ARCHIVE_DEBUG
952  LOG(llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
953 #endif
954  return t;
955  }
956 
957  return (title *)NULL;
958 }
959 
973 static void new_text_name(object *book, int msgtype) {
974  const char *name;
975 
976  if (book->type != BOOK)
977  return;
978 
979  switch (msgtype) {
980  case MSGTYPE_MONSTER:
982  break;
983 
984  case MSGTYPE_ARTIFACT:
986  break;
987 
988  case MSGTYPE_SPELLPATH:
990  break;
991 
992  case MSGTYPE_ALCHEMY:
994  break;
995 
996  case MSGTYPE_GODS:
998  break;
999 
1000  case MSGTYPE_MSGFILE:
1001  default:
1002  if (book->weight > 2000) { /* based on weight */
1004  } else {
1006  }
1007  break;
1008  }
1009  free_string(book->name);
1010  book->name = add_string(name);
1011 }
1012 
1022 static void add_author(object *op, int msgtype) {
1023  char title[MAX_BUF];
1024  const char *name;
1025 
1026  if (msgtype < 0 || strlen(op->msg) < 5)
1027  return;
1028 
1029  switch (msgtype) {
1030  case MSGTYPE_MONSTER:
1032  break;
1033 
1034  case MSGTYPE_ARTIFACT:
1036  break;
1037 
1038  case MSGTYPE_SPELLPATH:
1040  break;
1041 
1042  case MSGTYPE_ALCHEMY:
1044  break;
1045 
1046  case MSGTYPE_GODS:
1048  break;
1049 
1050  case MSGTYPE_MSGFILE:
1051  default:
1053  }
1054 
1055  snprintf(title, sizeof(title), "of %s", name);
1056  op->title = add_string(title);
1057 }
1058 
1070 static int unique_book(const object *book, int msgtype) {
1071  title *test;
1072 
1073  if (!booklist)
1074  return 1; /* No archival entries! Must be unique! */
1075 
1076  /* Go through the booklist. If the author and name match, not unique so
1077  * return 0.
1078  */
1079  for (test = get_titlelist(msgtype)->first_book; test; test = test->next) {
1080  if (!strcmp(test->name, book->name) && !strcmp(book->title, test->authour))
1081  return 0;
1082  }
1083  return 1;
1084 }
1085 
1094 static void add_book_to_list(const object *book, int msgtype) {
1095  titlelist *tl = get_titlelist(msgtype);
1096  title *t;
1097 
1098  if (!tl) {
1099  LOG(llevError, "add_book_to_list can't get booklist!\n");
1100  return;
1101  }
1102 
1103  t = get_empty_book();
1104  t->name = add_string(book->name);
1105  t->authour = add_string(book->title);
1106  t->size = strlen(book->msg);
1107  t->msg_index = strtoint(book->msg);
1108  t->archname = add_string(book->arch->name);
1109  t->level = book->level;
1110 
1111  t->next = tl->first_book;
1112  tl->first_book = t;
1113  tl->number++;
1114 
1115  /* We have stuff we need to write now */
1117 
1118 #ifdef ARCHIVE_DEBUG
1119  LOG(llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
1120 #endif
1121 }
1122 
1136 static void change_book(object *book, int msgtype) {
1137  titlelist *tl;
1138  title *t;
1139  int tries;
1140 
1141  if (book->type != BOOK) {
1142  LOG(llevError, "change_book_name() called w/ illegal obj type.\n");
1143  return;
1144  }
1145 
1146  tl = get_titlelist(msgtype);
1147  t = NULL;
1148  tries = 0;
1149 
1150  /* look to see if our msg already been archived. If so, alter
1151  * the book to match the archival text. If we fail to match,
1152  * then we archive the new title/name/msg combo if there is
1153  * room on the titlelist.
1154  */
1155 
1156  if (strlen(book->msg) > 5 && (t = find_title(book, msgtype))) {
1157  object *tmpbook;
1158  sstring marker = object_get_value(book, "knowledge_marker");
1159 
1160  /* alter book properties */
1161  tmpbook = create_archetype(t->archname);
1162  if (marker != NULL)
1163  /* need to copy the knowledge_marker */
1164  object_set_value(tmpbook, "knowledge_marker", marker, 1);
1165  object_set_msg(tmpbook, book->msg);
1166  object_copy(tmpbook, book);
1167  object_free_drop_inventory(tmpbook);
1168 
1169  book->title = add_string(t->authour);
1170  free_string(book->name);
1171  book->name = add_string(t->name);
1172  book->level = t->level;
1173  } else { /* Don't have any default title, so lets make up a new one */
1174  int numb, maxnames = max_titles[msgtype];
1175  const char *old_title;
1176  const char *old_name;
1177 
1178  old_title = book->title ? add_string(book->title) : NULL;
1179  old_name = add_string(book->name);
1180 
1181  /* some pre-generated books have title already set (from
1182  * maps), also don't bother looking for unique title if
1183  * we already used up all the available names! */
1184 
1185  if (!tl) {
1186  LOG(llevError, "change_book_name(): can't find title list\n");
1187  numb = 0;
1188  } else
1189  numb = tl->number;
1190 
1191  if (numb == maxnames) {
1192 #ifdef ARCHIVE_DEBUG
1193  LOG(llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1194 #endif
1195  // Set tries to maximum. That way we get the descriptors on books when the
1196  // title set is full, too.
1197  tries = MAX_TITLE_CHECK;
1198  }
1199  /* shouldnt change map-maker books */
1200  else if (!book->title)
1201  do {
1202  /* random book name */
1203  new_text_name(book, msgtype);
1204  add_author(book, msgtype); /* random author */
1205  tries++;
1206  } while (!unique_book(book, msgtype) && tries < MAX_TITLE_CHECK);
1207 
1208  /* Now deal with 2 cases.
1209  * 1) If no space for a new title exists lets just restore
1210  * the old book properties. Remember, if the book had
1211  * matchd an older entry on the titlelist, we shouldnt
1212  * have called this routine in the first place!
1213  * 2) If we got a unique title, we need to add it to
1214  * the list.
1215  */
1216 
1217  if (tries == MAX_TITLE_CHECK) {
1218 #ifdef ARCHIVE_DEBUG
1219  LOG(llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1220 #endif
1221  /* restore old book properties here */
1222  free_string(book->name);
1223  if (book->title)
1224  free_string(book->title);
1225  book->title = old_title != NULL ? add_string(old_title) : NULL;
1226 
1227  if (RANDOM()%4) {
1228  /* Lets give the book a description to individualize it some */
1229  char new_name[MAX_BUF];
1230 
1231  snprintf(new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM()%arraysize(book_descrpt)], old_name);
1232  book->name = add_string(new_name);
1233  } else {
1234  book->name = add_string(old_name);
1235  }
1236  } else if (book->title && strlen(book->msg) > 5) { /* archive if long msg texts */
1237  add_book_to_list(book, msgtype);
1238  }
1239 
1240  if (old_title != NULL)
1241  free_string(old_title);
1242  free_string(old_name);
1243  }
1244 }
1245 
1246 /*****************************************************************************
1247  *
1248  * This is the start of the area that generates the actual contents
1249  * of the book.
1250  *
1251  *****************************************************************************/
1252 
1253 /*****************************************************************************
1254  * Monster msg generation code.
1255  ****************************************************************************/
1256 
1268 object *get_random_mon(int level) {
1269 
1270  /* safety check. Problem w/ init_mon_info list? */
1271  if (monsters.empty())
1272  return (object *)NULL;
1273 
1274  if (!level) {
1275  return monsters[RANDOM() % monsters.size()];
1276  }
1277 
1278  std::vector<object *> select;
1279  std::copy_if(monsters.cbegin(), monsters.cend(), std::back_inserter(select), [&] (auto ob) { return ob->level >= level; });
1280 
1281  if (select.empty()) {
1282  LOG(llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1283  return NULL;
1284  }
1285  return select[RANDOM() % select.size()];
1286 }
1287 
1297 static StringBuffer *mon_desc(const object *mon) {
1298  StringBuffer *desc = stringbuffer_new();
1299  stringbuffer_append_printf(desc, "\n---\n *** %s ***\n", mon->name);
1300  describe_item(mon, NULL, 0, desc);
1301  return desc;
1302 }
1303 
1315 static object *get_next_mon(const object *tmp) {
1316  auto it = std::find(monsters.begin(), monsters.end(), tmp);
1317  if (it == monsters.end())
1318  return nullptr;
1319  ++it;
1320  if (it == monsters.end())
1321  it = monsters.begin();
1322 
1323  return *it;
1324 }
1325 
1338 static StringBuffer *mon_info_msg(int level, size_t booksize, object *book) {
1339  object *tmp;
1340  StringBuffer *marker = stringbuffer_new(), *desc = stringbuffer_new(), *mon = NULL;
1341  int added = 0;
1342  sstring final;
1343  const char *sep = ":";
1344 
1345  /*preamble */
1346  stringbuffer_append_string(desc, "This beastiary contains:");
1347  stringbuffer_append_string(marker, "monster");
1348 
1349  /* lets print info on as many monsters as will fit in our
1350  * document.
1351  * 8-96 Had to change this a bit, otherwise there would
1352  * have been an impossibly large number of combinations
1353  * of text! (and flood out the available number of titles
1354  * in the archive in a snap!) -b.t.
1355  */
1356  for (tmp = get_random_mon(level*3); tmp; tmp = get_next_mon(tmp)) {
1357  /* monster description */
1358  mon = mon_desc(tmp);
1359 
1361  break;
1362  added++;
1363  stringbuffer_append_printf(marker, "%s%s", sep, tmp->arch->name);
1364  sep = "/";
1367  mon = NULL;
1368  }
1369 
1370  if (mon != NULL) {
1372  }
1373 
1374  final = stringbuffer_finish_shared(marker);
1375  if (added)
1376  object_set_value(book, "knowledge_marker", final, 1);
1377  free_string(final);
1378 
1379  return desc;
1380 }
1381 
1382 /*****************************************************************************
1383  * Artifact msg generation code.
1384  ****************************************************************************/
1385 
1395 static StringBuffer *artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator) {
1396  object *tmp;
1397  int chance;
1398  StringBuffer *desc = stringbuffer_new(), *sbuf;
1399 
1400  if (separator)
1401  stringbuffer_append_string(desc, "---\n");
1402 
1403  /* Name */
1404  if (!art->allowed.empty()) {
1405  archetype *arch;
1406  auto name = art->allowed[RANDOM() % art->allowed.size()];
1407  int inv = 0;
1408 
1409  if (name[0] == '!')
1410  inv = 1;
1411 
1414  if (!arch)
1416 
1417  if (!arch)
1418  LOG(llevError, "artifact_msg: missing archetype %s for artifact %s (type %d)\n", name + inv, art->item->name, art->item->type);
1419  else {
1420  if (inv)
1421  stringbuffer_append_printf(desc, " A %s (excepted %s) of %s", art_name_array[art_name].name, arch->clone.name_pl, art->item->name);
1422  else
1423  stringbuffer_append_printf(desc, " A %s of %s", arch->clone.name, art->item->name);
1424  }
1425  } else { /* default name is used */
1426  /* use the base 'generic' name for our artifact */
1427  stringbuffer_append_printf(desc, " The %s of %s", art_name_array[art_name].name, art->item->name);
1428  }
1429 
1430  /* chance of finding */
1431  stringbuffer_append_string(desc, " is ");
1432  chance = 100*((float)art->chance/al->total_chance);
1433  if (chance >= 20)
1434  stringbuffer_append_string(desc, "an uncommon");
1435  else if (chance >= 10)
1436  stringbuffer_append_string(desc, "an unusual");
1437  else if (chance >= 5)
1438  stringbuffer_append_string(desc, "a rare");
1439  else
1440  stringbuffer_append_string(desc, "a very rare");
1441 
1442  /* value of artifact */
1443  stringbuffer_append_printf(desc, " item with a value that is %d times normal.\n", art->item->value);
1444 
1445  /* include the message about the artifact, if exists, and book
1446  * level is kinda high */
1447  if (message && !(strlen(art->item->msg) > BOOK_BUF))
1448  stringbuffer_append_string(desc, art->item->msg);
1449 
1450  /* properties of the artifact */
1451  tmp = object_new();
1452  add_abilities(tmp, art->item);
1453  tmp->type = al->type;
1455  sbuf = describe_item(tmp, NULL, 0, NULL);
1456  if (stringbuffer_length(sbuf) > 1) {
1457  stringbuffer_append_string(desc, " Properties of this artifact include:\n ");
1459  stringbuffer_append_string(desc, "\n");
1460  }
1461  free(stringbuffer_finish(sbuf));
1463 
1464  return desc;
1465 }
1466 
1478 static StringBuffer *artifact_msg(unsigned int level, size_t booksize) {
1479  const artifactlist *al;
1480  const artifact *art;
1481  int i, type, index;
1482  int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
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 {
1498  al = find_artifactlist(type);
1499  i++;
1500  } while (al == NULL && i < 10);
1501 
1502  if (i == 10) { /* Unable to find a message */
1504  return message;
1505  }
1506 
1507  /* There is no reason to start on the artifact list at the beginning. Lets
1508  * take our starting position randomly... */
1509  auto iart = al->items.cbegin();
1510  for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
1511  if (iart == al->items.cend())
1512  iart = al->items.cbegin(); /* hmm, out of stuff, loop back around */
1513  ++iart;
1514  }
1515 
1516  /* Ok, lets print out the contents */
1517  stringbuffer_append_printf(message, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1518 
1519  i = 0;
1520  /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1521  * as long as we have space up to the allowed max # (book_entires)
1522  */
1523  while (book_entries > 0) {
1524  int with_message;
1525  if (iart == al->items.cend())
1526  iart = al->items.cbegin();
1527  art = *iart;
1528  with_message = (art->item->msg && RANDOM()%4+1 < level) ? 1 : 0;
1529 
1530  desc = artifact_describe(art, al, with_message, index, i++);
1531 
1533  stringbuffer_delete(desc);
1534  break;
1535  }
1536 
1538  stringbuffer_delete(desc);
1539 
1540  ++iart;
1541  book_entries--;
1542  }
1543 
1544  return message;
1545 }
1546 
1547 /*****************************************************************************
1548  * Spellpath message generation
1549  *****************************************************************************/
1550 
1552 static struct {
1553  int prayers;
1554  int did_first_sp;
1555  uint32_t pnum;
1556  int level;
1557  size_t booksize;
1559  int done;
1563 static void do_spellpath_msg(archetype *at) {
1564  /* Determine if this is an appropriate spell. Must
1565  * be of matching path, must be of appropriate type (prayer
1566  * or not), and must be within the valid level range.
1567  */
1568  if (at->clone.type == SPELL
1569  && at->clone.path_attuned & sp_params.pnum
1570  && ((at->clone.stats.grace && sp_params.prayers) || (at->clone.stats.sp && !sp_params.prayers))
1571  && at->clone.level < sp_params.level*8) {
1572  if (strlen(at->clone.name) + stringbuffer_length(sp_params.buf) >= sp_params.booksize) {
1573  sp_params.done = 1;
1574  return;
1575  }
1576 
1577  if (sp_params.did_first_sp)
1579  sp_params.did_first_sp = 1;
1581  }
1582 }
1583 
1598  int path = RANDOM()%NRSPELLPATHS;
1599  sp_params.prayers = RANDOM()%2;
1600  sp_params.did_first_sp = 0;
1601  sp_params.pnum = spellpathdef[path];
1602  sp_params.done = 0;
1603 
1604  if (buf == NULL) {
1605  buf = stringbuffer_new();
1606  /* Preamble */
1607  stringbuffer_append_printf(buf, "Herein are detailed the names of %s", sp_params.prayers ? "prayers" : "incantations");
1608  stringbuffer_append_printf(buf, " belonging to the path of %s:\n ", spellpathnames[path]);
1609  }
1610  sp_params.level = level;
1611  sp_params.booksize = booksize;
1612  sp_params.buf = buf;
1613 
1615 
1616  /* Geez, no spells were generated. */
1617  if (!sp_params.did_first_sp) {
1618  if (RANDOM()%4) { /* usually, lets make a recursive call... */
1619  // If we do a recursive call, we reset the spell path, so we will want to reset our text as well.
1621  return spellpath_msg(level, booksize, NULL);
1622  }
1623  /* give up, cause knowing no spells exist for path is info too. need the header too. */
1624  stringbuffer_append_string(buf, "- no known spells exist -\n");
1625  }
1626  return buf;
1627 }
1628 
1637 static void make_formula_book(object *book, int level) {
1638  recipelist *fl;
1639  recipe *formula;
1640  int chance, count = 0;
1641  const char *op_name;
1642  archetype *at;
1643  StringBuffer *text, *title;
1644  char *final, km[MAX_BUF];
1645 
1646  /* the higher the book level, the more complex (ie number of
1647  * ingredients) the formula can be.
1648  */
1649  fl = get_formulalist((RANDOM()%level)/3+1);
1650  if (!fl)
1651  fl = get_formulalist(1); /* safety */
1652 
1653  if (fl->total_chance == 0) {
1654  object_set_msg(book, " <indecipherable text>\n");
1656  add_author(book, MSGTYPE_ALCHEMY);
1657  return;
1658  }
1659 
1660  /* get a random formula, weighted by its bookchance */
1661  chance = RANDOM()%fl->total_chance;
1662  for (formula = fl->items; formula != NULL; formula = formula->next) {
1663  chance -= formula->chance;
1664  if (chance <= 0 && formula->chance != 0 && !formula->is_combination)
1665  break;
1666  }
1667 
1668  if (!formula || formula->arch_names <= 0) {
1669  object_set_msg(book, " <indecipherable text>\n");
1671  add_author(book, MSGTYPE_ALCHEMY);
1672  return;
1673  }
1674 
1675  /* looks like a formula was found. Base the amount
1676  * of information on the booklevel and the spellevel
1677  * of the formula. */
1678 
1679  op_name = formula->arch_name[RANDOM()%formula->arch_names];
1680  at = find_archetype(op_name);
1681  if (at == (archetype *)NULL) {
1682  LOG(llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1683  object_set_msg(book, " <indecipherable text>\n");
1685  add_author(book, MSGTYPE_ALCHEMY);
1686  return;
1687  }
1688  op_name = at->clone.name;
1689 
1690  text = stringbuffer_new();
1691  title = stringbuffer_new();
1692 
1693  /* preamble */
1694  stringbuffer_append_printf(text, "Herein is described a%s %s project using %s:\n",
1695  formula->diff >= 10 && formula->diff < 15 ? "n" : "",
1697  formula->skill ? formula->skill : "an unknown skill");
1698 
1699  /* item name */
1700  if (strcmp(formula->title, "NONE")) {
1701  stringbuffer_append_printf(text, "The %s of %s", op_name, formula->title);
1702  /* This results in things like pile of philo. sulfur.
1703  * while philo. sulfur may look better, without this,
1704  * you get things like 'the wise' because its missing the
1705  * water of section.
1706  */
1708  } else {
1709  stringbuffer_append_printf(text, "The %s", op_name);
1711  if (at->clone.title) {
1714  }
1715  }
1716  /* Lets name the book something meaningful ! */
1717  if (book->name)
1718  free_string(book->name);
1720  if (book->title) {
1721  free_string(book->title);
1722  book->title = NULL;
1723  }
1724 
1725  /* ingredients to make it */
1726  if (formula->ingred != NULL) {
1727  linked_char *next;
1728  archetype *at;
1729  char name[MAX_BUF];
1730 
1731  at = find_archetype(formula->cauldron);
1732  if (at)
1733  query_name(&at->clone, name, MAX_BUF);
1734  else
1735  snprintf(name, sizeof(name), "an unknown place");
1736 
1737  stringbuffer_append_printf(text, " may be made at %s using the following ingredients:\n", name);
1738 
1739  for (next = formula->ingred; next != NULL; next = next->next) {
1740  count++;
1741  stringbuffer_append_printf(text, "%s\n", next->name);
1742  }
1743  } else {
1744  LOG(llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, formula->title);
1746  }
1747 
1748  final = stringbuffer_finish(text);
1749  object_set_msg(book, final);
1750  free(final);
1751 
1754  snprintf(km, sizeof(km), "alchemy:%d:%d:%s", count, formula->index, formula->title);
1755  object_set_value(book, "knowledge_marker", km, 1);
1756 }
1757 
1768 static StringBuffer *msgfile_msg(object *book, size_t booksize) {
1769  StringBuffer *ret = stringbuffer_new();
1770 
1772 
1773  if (msg && strlen(msg->message) <= booksize) {
1774  stringbuffer_append_string(ret, msg->message);
1775  if (msg->identifier != NULL) {
1776  char km[HUGE_BUF];
1779  snprintf(km, sizeof(km), "message:%s", msg->identifier);
1780  object_set_value(book, "knowledge_marker", km, 1);
1781  }
1782  if (msg->quest_code) {
1783  /* add a 'apply' hook to launch the quest */
1784  archetype *at = find_archetype("quest_advance_apply");
1785  if (at != NULL) {
1786  object *event = object_create_arch(at);
1787  FREE_AND_COPY(event->name, msg->quest_code);
1788  object_insert_in_ob(event, book);
1789  }
1790  }
1791  } else {
1792 #ifdef BOOK_MSG_DEBUG
1793  // If msg was defined when we got here, we overflowed a book.
1794  if (msg)
1795  LOG(llevDebug, "Could not fit message %s into %s (%ld > %ld)\n", msg->identifier, book->name, strlen(msg->message), booksize);
1796 #endif
1797  stringbuffer_append_string(ret, "\n <undecipherable text>");
1798  }
1799 
1800  return ret;
1801 }
1802 
1817 static StringBuffer *god_info_msg(int level, size_t booksize, object *book) {
1818  int what = 0;
1819  const object *god = get_rand_god();
1820  StringBuffer *desc = NULL;
1821 
1822  if (!god)
1823  return NULL; /* oops, problems... */
1824 
1825  if (booksize > BOOK_BUF) {
1826  LOG(llevError, "common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (unsigned long)booksize, BOOK_BUF);
1827  booksize = BOOK_BUF;
1828  }
1829 
1830  if (level >= 2 && RANDOM()%2) {
1831  what |= GOD_ENEMY;
1832  }
1833  if (level >= 3 && RANDOM()%2) {
1834  what |= GOD_HOLYWORD;
1835  }
1836  if (level >= 4 && RANDOM()%2) {
1837  what |= GOD_RESISTANCES;
1838  }
1839  if (level >= 5 && RANDOM()%2) {
1840  what |= GOD_SACRED;
1841  }
1842  if (level >= 6 && RANDOM()%2) {
1843  what |= GOD_BLESSED;
1844  }
1845  if (level >= 8 && RANDOM()%2) {
1846  what |= GOD_IMMUNITIES;
1847  }
1848  if (level >= 12 && RANDOM()%2) {
1849  what |= GOD_PATHS;
1850  }
1851 
1852  desc = stringbuffer_new();
1853  what = describe_god(god, what, desc, booksize);
1854 
1855  /* check to be sure new buffer size dont exceed either
1856  * the maximum buffer size, or the 'natural' size of the
1857  * book... */
1858  if (stringbuffer_length(desc) > 1 && stringbuffer_length(desc) <= booksize) {
1859  char buf[BOOK_BUF];
1860  snprintf(buf, sizeof(buf), "god:%s:%d", god->name, what);
1861  object_set_value(book, "knowledge_marker", buf, 1);
1862  return desc;
1863  }
1864 
1865  stringbuffer_delete(desc);
1866  return NULL;
1867 }
1868 
1887 void tailor_readable_ob(object *book, int msg_type) {
1888  int level = book->level ? RANDOM()%book->level+1 : 1;
1889  size_t book_buf_size;
1890  StringBuffer *message = NULL;
1891 
1892  /* safety */
1893  if (book->type != BOOK)
1894  return;
1895 
1896  if (level <= 0)
1897  return; /* if no level no point in doing any more... */
1898 
1899  /* Max text length this book can have. */
1900  book_buf_size = BOOKSIZE(book);
1901  book_buf_size -= strlen("\n"); /* Keep enough for final \n. */
1902  assert(book_buf_size < BOOK_BUF);
1903 
1904  /* &&& The message switch &&& */
1905  /* Below all of the possible types of messages in the "book"s.
1906  */
1907  /*
1908  * IF you add a new type of book msg, you will have to do several things.
1909  * 1) make sure there is an entry in the msg switch below!
1910  * 2) make sure there is an entry in max_titles[] array.
1911  * 3) make sure there are entries for your case in new_text_title()
1912  * and add_authour().
1913  * 4) you may want separate authour/book name arrays in read.h
1914  */
1915 
1916  if (msg_type >= (int)arraysize(max_titles))
1917  msg_type = 0;
1918 
1919  msg_type = msg_type > 0 ? msg_type : (int)(RANDOM()%6);
1920  switch (msg_type) {
1921  case MSGTYPE_MONSTER:
1922  message = mon_info_msg(level, book_buf_size, book);
1923  break;
1924 
1925  case MSGTYPE_ARTIFACT:
1926  message = artifact_msg(level, book_buf_size);
1927  break;
1928 
1929  case MSGTYPE_SPELLPATH: /* grouping incantations/prayers by path */
1930  message = spellpath_msg(level, book_buf_size, NULL);
1931  break;
1932 
1933  case MSGTYPE_ALCHEMY: /* describe an alchemy formula */
1934  make_formula_book(book, level);
1935  /* make_formula_book already gives title */
1936  return;
1937  break;
1938 
1939  case MSGTYPE_GODS: /* bits of information about a god */
1940  message = god_info_msg(level, book_buf_size, book);
1941  break;
1942 
1943  case MSGTYPE_LIB: /* use info list in lib/ */
1944  default:
1945  message = msgfile_msg(book, book_buf_size);
1946  break;
1947  }
1948 
1949  if (message != NULL) {
1950  char *final;
1952  final = stringbuffer_finish(message);
1953  object_set_msg(book, final);
1954  free(final);
1955  /* lets give the "book" a new name, which may be a compound word */
1956  change_book(book, msg_type);
1957  }
1958 }
1959 
1960 /*****************************************************************************
1961  *
1962  * Cleanup routine for readable stuff.
1963  *
1964  *****************************************************************************/
1965 
1969 void free_all_readable(void) {
1970  titlelist *tlist, *tnext;
1971  title *title1, *titlenext;
1972 
1973  LOG(llevDebug, "freeing all book information\n");
1974 
1975  for (tlist = booklist; tlist != NULL; tlist = tnext) {
1976  tnext = tlist->next;
1977  for (title1 = tlist->first_book; title1; title1 = titlenext) {
1978  titlenext = title1->next;
1979  if (title1->name)
1980  free_string(title1->name);
1981  if (title1->authour)
1982  free_string(title1->authour);
1983  if (title1->archname)
1984  free_string(title1->archname);
1985  free(title1);
1986  }
1987  free(tlist);
1988  }
1989 }
1990 
1991 /*****************************************************************************
1992  *
1993  * Writeback routine for updating the bookarchive.
1994  *
1995  ****************************************************************************/
1996 
2001  FILE *fp;
2002  OutputFile of;
2003  int index;
2004  char fname[MAX_BUF];
2005  title *book;
2006  titlelist *bl;
2007 
2008  /* If nothing changed, don't write anything */
2010  return;
2011 
2012  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
2013  LOG(llevDebug, "Updating book archive: %s...\n", fname);
2014 
2015  fp = of_open(&of, fname);
2016  if (fp == NULL)
2017  return;
2018 
2019  for (bl = get_titlelist(0), index = 0; bl; bl = bl->next, index++) {
2020  for (book = bl->first_book; book; book = book->next)
2021  if (book && book->authour) {
2022  fprintf(fp, "title %s\n", book->name);
2023  fprintf(fp, "authour %s\n", book->authour);
2024  fprintf(fp, "arch %s\n", book->archname);
2025  fprintf(fp, "level %d\n", book->level);
2026  fprintf(fp, "type %d\n", index);
2027  /* C89 doesn't have %zu... */
2028  fprintf(fp, "size %lu\n", (unsigned long)book->size);
2029  fprintf(fp, "index %d\n", book->msg_index);
2030  fprintf(fp, "end\n");
2031  }
2032  }
2033  if (!of_close(&of))
2034  return;
2035 
2036  if (chmod(fname, SAVE_MODE) != 0) {
2037  LOG(llevError, "Could not set permissions on '%s'\n", fname);
2038  }
2039 
2041 }
2042 
2051  uint8_t subtype = readable->subtype;
2052 
2053  if (subtype > last_readable_subtype)
2054  return &readable_message_types[0];
2055  return &readable_message_types[subtype];
2056 }
2057 
2064  return message->title;
2065 }
2066 
2073  return message->message;
2074 }
2075 
2082  return message->face;
2083 }
write_book_archive
void write_book_archive(void)
Definition: readable.cpp:2000
PATH_TURNING
#define PATH_TURNING
Definition: spells.h:29
MSG_TYPE_MONUMENT_WALL_2
#define MSG_TYPE_MONUMENT_WALL_2
Definition: newclient.h:472
give.next
def next
Definition: give.py:44
Face
Definition: face.h:14
formula_book_name
static const char *const formula_book_name[]
Definition: readable.cpp:341
MSG_TYPE_BOOK_SPELL_PRAYER
#define MSG_TYPE_BOOK_SPELL_PRAYER
Definition: newclient.h:419
output_file.h
global.h
GOD_IMMUNITIES
#define GOD_IMMUNITIES
Definition: god.h:18
change_book
static void change_book(object *book, int msgtype)
Definition: readable.cpp:1136
settings
struct Settings settings
Definition: init.cpp:139
path_book_name
static const char *const path_book_name[]
Definition: readable.cpp:173
stringbuffer_length
size_t stringbuffer_length(StringBuffer *sb)
Definition: stringbuffer.cpp:218
GeneralMessage
Definition: book.h:44
get_formulalist
recipelist * get_formulalist(int i)
Definition: recipe.cpp:98
SAVE_MODE
#define SAVE_MODE
Definition: config.h:563
title::authour
const char * authour
Definition: readable.cpp:110
get_empty_booklist
static titlelist * get_empty_booklist(void)
Definition: readable.cpp:575
do_spellpath_msg
static void do_spellpath_msg(archetype *at)
Definition: readable.cpp:1563
mon_author
static const char *const mon_author[]
Definition: readable.cpp:282
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
PATH_LIGHT
#define PATH_LIGHT
Definition: spells.h:32
llevError
@ llevError
Definition: logger.h:11
init_mon_info
static void init_mon_info(void)
Definition: readable.cpp:885
GOD_PATHS
#define GOD_PATHS
Definition: god.h:19
PATH_RESTORE
#define PATH_RESTORE
Definition: spells.h:21
object::path_attuned
uint32_t path_attuned
Definition: object.h:353
get_empty_book
static title * get_empty_book(void)
Definition: readable.cpp:592
MSG_TYPE_PAPER_LETTER_OLD_2
#define MSG_TYPE_PAPER_LETTER_OLD_2
Definition: newclient.h:443
PATH_INFO
#define PATH_INFO
Definition: spells.h:26
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
arraysize
#define arraysize(arrayname)
Definition: readable.cpp:98
MSG_TYPE_BOOK_SPELL_SUMMONER
#define MSG_TYPE_BOOK_SPELL_SUMMONER
Definition: newclient.h:422
book_author
static const char *const book_author[]
Definition: readable.cpp:410
of_close
int of_close(OutputFile *of)
Definition: output_file.cpp:61
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
MONSTER_EXCLUDE_FROM_READABLE_KEY
#define MONSTER_EXCLUDE_FROM_READABLE_KEY
Definition: object.h:587
free_all_readable
void free_all_readable(void)
Definition: readable.cpp:1969
AssetsManager::messages
Messages * messages()
Definition: AssetsManager.h:59
PATH_ELEC
#define PATH_ELEC
Definition: spells.h:16
monsters
static std::vector< object * > monsters
Definition: readable.cpp:142
of_open
FILE * of_open(OutputFile *of, const char *fname)
Definition: output_file.cpp:30
GLOVES
@ GLOVES
Definition: object.h:218
arttypename::name
const char * name
Definition: readable.cpp:129
GIRDLE
@ GIRDLE
Definition: object.h:228
PATH_FIRE
#define PATH_FIRE
Definition: spells.h:14
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
recipe::arch_names
size_t arch_names
Definition: recipe.h:12
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:301
AssetsManager.h
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:239
mon_book_name
static const char *const mon_book_name[]
Definition: readable.cpp:261
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Definition: stringbuffer.cpp:138
path_author
static const char *const path_author[]
Definition: readable.cpp:183
artifact_msg
static StringBuffer * artifact_msg(unsigned int level, size_t booksize)
Definition: readable.cpp:1478
MSG_TYPE_PAPER
#define MSG_TYPE_PAPER
Definition: newclient.h:386
MSG_TYPE_PAPER_LETTER_NEW_2
#define MSG_TYPE_PAPER_LETTER_NEW_2
Definition: newclient.h:445
object::arch
struct archetype * arch
Definition: object.h:422
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
MSG_TYPE_BOOK_QUARTO_1
#define MSG_TYPE_BOOK_QUARTO_1
Definition: newclient.h:416
PATH_SELF
#define PATH_SELF
Definition: spells.h:18
MSG_TYPE_SIGN_BASIC
#define MSG_TYPE_SIGN_BASIC
Definition: newclient.h:455
artifactlist::items
std::vector< artifact * > items
Definition: artifact.h:28
gods_book_name
static const char *const gods_book_name[]
Definition: readable.cpp:303
ARMOUR
@ ARMOUR
Definition: object.h:125
MSG_TYPE_PAPER_SCROLL_NEW_2
#define MSG_TYPE_PAPER_SCROLL_NEW_2
Definition: newclient.h:451
WEAPON
@ WEAPON
Definition: object.h:124
MSG_TYPE_PAPER_SCROLL_OLD_2
#define MSG_TYPE_PAPER_SCROLL_OLD_2
Definition: newclient.h:449
MSG_TYPE_PAPER_NOTE_2
#define MSG_TYPE_PAPER_NOTE_2
Definition: newclient.h:440
guildjoin.ob
ob
Definition: guildjoin.py:42
MSG_TYPE_CARD_MONEY_2
#define MSG_TYPE_CARD_MONEY_2
Definition: newclient.h:435
MSG_TYPE_MONUMENT_STATUE_3
#define MSG_TYPE_MONUMENT_STATUE_3
Definition: newclient.h:467
artifact::item
object * item
Definition: artifact.h:15
commongive.inv
inv
Definition: commongive.py:29
god_info_msg
static StringBuffer * god_info_msg(int level, size_t booksize, object *book)
Definition: readable.cpp:1817
add_abilities
void add_abilities(object *op, const object *change)
Definition: artifact.cpp:320
AMULET
@ AMULET
Definition: object.h:144
recipelist::items
recipe * items
Definition: recipe.h:40
archetype::head
archetype * head
Definition: object.h:476
MSG_TYPE_PAPER_LETTER_OLD_1
#define MSG_TYPE_PAPER_LETTER_OLD_1
Definition: newclient.h:442
strtoktolin
char * strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size)
Definition: readable.cpp:683
MSG_TYPE_SIGN_DIR_RIGHT
#define MSG_TYPE_SIGN_DIR_RIGHT
Definition: newclient.h:457
mon
object * mon
Definition: comet_perf.cpp:75
gods_author
static const char *const gods_author[]
Definition: readable.cpp:320
title::name
const char * name
Definition: readable.cpp:109
MSG_TYPE_CARD_SIMPLE_2
#define MSG_TYPE_CARD_SIMPLE_2
Definition: newclient.h:426
SKILL
@ SKILL
Definition: object.h:148
titlelist
Definition: readable.cpp:121
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.cpp:1192
Ice.tmp
int tmp
Definition: Ice.py:207
recipe::arch_name
char ** arch_name
Definition: recipe.h:13
artifact::allowed
std::vector< sstring > allowed
Definition: artifact.h:18
MSG_TYPE_BOOK_CLASP_2
#define MSG_TYPE_BOOK_CLASP_2
Definition: newclient.h:413
MSG_TYPE_CARD
#define MSG_TYPE_CARD
Definition: newclient.h:385
prayers
int prayers
Definition: readable.cpp:1555
booksize
size_t booksize
Definition: readable.cpp:1559
MSGTYPE_MONSTER
#define MSGTYPE_MONSTER
Definition: readable.cpp:81
MSG_TYPE_BOOK_ELEGANT_1
#define MSG_TYPE_BOOK_ELEGANT_1
Definition: newclient.h:414
object::title
sstring title
Definition: object.h:325
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
GOD_BLESSED
#define GOD_BLESSED
Definition: god.h:17
object::level
int16_t level
Definition: object.h:361
buf
StringBuffer * buf
Definition: readable.cpp:1560
title::size
size_t size
Definition: readable.cpp:113
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2853
recipelist::total_chance
int total_chance
Definition: recipe.h:38
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
PATH_ABJURE
#define PATH_ABJURE
Definition: spells.h:20
readable_message_types
static const readable_message_type readable_message_types[]
Definition: readable.cpp:484
GOD_HOLYWORD
#define GOD_HOLYWORD
Definition: god.h:14
titlelist::first_book
title * first_book
Definition: readable.cpp:123
linked_char
Definition: global.h:96
recipe::is_combination
int is_combination
Definition: recipe.h:31
find_title
static title * find_title(const object *book, int msgtype)
Definition: readable.cpp:934
get_next_mon
static object * get_next_mon(const object *tmp)
Definition: readable.cpp:1315
MSG_TYPE_PAPER_SCROLL_OLD_1
#define MSG_TYPE_PAPER_SCROLL_OLD_1
Definition: newclient.h:448
need_to_write_bookarchive
static int need_to_write_bookarchive
Definition: readable.cpp:144
MSG_TYPE_CARD_STRANGE_1
#define MSG_TYPE_CARD_STRANGE_1
Definition: newclient.h:431
PATH_MISSILE
#define PATH_MISSILE
Definition: spells.h:17
CLOAK
@ CLOAK
Definition: object.h:209
Messages::random
GeneralMessage * random()
Definition: Messages.cpp:50
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
MSGTYPE_MSGFILE
#define MSGTYPE_MSGFILE
Definition: readable.cpp:91
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1560
add_author
static void add_author(object *op, int msgtype)
Definition: readable.cpp:1022
HELMET
@ HELMET
Definition: object.h:141
get_rand_god
const object * get_rand_god(void)
Definition: holy.cpp:73
object::subtype
uint8_t subtype
Definition: object.h:349
recipelist
Definition: recipe.h:37
MSG_TYPE_MONUMENT_GRAVESTONE_1
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
Definition: newclient.h:468
PATH_WOUNDING
#define PATH_WOUNDING
Definition: spells.h:30
MSG_TYPE_MONUMENT
#define MSG_TYPE_MONUMENT
Definition: newclient.h:388
PATH_CREATE
#define PATH_CREATE
Definition: spells.h:24
MSG_TYPE_CARD_STRANGE_2
#define MSG_TYPE_CARD_STRANGE_2
Definition: newclient.h:432
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
MSG_TYPE_SIGN_DIR_BOTH
#define MSG_TYPE_SIGN_DIR_BOTH
Definition: newclient.h:458
MSG_TYPE_MONUMENT_GRAVESTONE_2
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
Definition: newclient.h:469
get_titlelist
static titlelist * get_titlelist(int i)
Definition: readable.cpp:610
PATH_DETONATE
#define PATH_DETONATE
Definition: spells.h:22
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Definition: stringbuffer.cpp:85
MSG_TYPE_SIGN_DIR_LEFT
#define MSG_TYPE_SIGN_DIR_LEFT
Definition: newclient.h:456
archetype::clone
object clone
Definition: object.h:478
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
MSG_TYPE_BOOK_CLASP_1
#define MSG_TYPE_BOOK_CLASP_1
Definition: newclient.h:412
book_descrpt
static const char *const book_descrpt[]
Definition: readable.cpp:457
ROD
@ ROD
Definition: object.h:114
init_readable
void init_readable(void)
Definition: readable.cpp:903
titlelist::next
titlelist * next
Definition: readable.cpp:124
python_init.path
path
Definition: python_init.py:8
done
int done
Definition: readable.cpp:1561
init_book_archive
static void init_book_archive(void)
Definition: readable.cpp:737
tailor_readable_ob
void tailor_readable_ob(object *book, int msg_type)
Definition: readable.cpp:1887
spellpath_msg
static StringBuffer * spellpath_msg(int level, size_t booksize, StringBuffer *buf)
Definition: readable.cpp:1597
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
object::value
int32_t value
Definition: object.h:360
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
MSG_TYPE_MONUMENT_STATUE_2
#define MSG_TYPE_MONUMENT_STATUE_2
Definition: newclient.h:466
add_book_to_list
static void add_book_to_list(const object *book, int msgtype)
Definition: readable.cpp:1094
object::type
uint8_t type
Definition: object.h:348
PATH_SUMMON
#define PATH_SUMMON
Definition: spells.h:19
MSG_TYPE_CARD_ELEGANT_1
#define MSG_TYPE_CARD_ELEGANT_1
Definition: newclient.h:428
recipe::index
int index
Definition: recipe.h:18
object_create_arch
object * object_create_arch(archetype *at)
Definition: arch.cpp:298
book.h
MAX_TITLE_CHECK
#define MAX_TITLE_CHECK
Definition: readable.cpp:76
title
Definition: readable.cpp:108
artifactlist
Definition: artifact.h:24
arttypename
Definition: readable.cpp:128
PATH_TRANSFER
#define PATH_TRANSFER
Definition: spells.h:28
disinfect.count
int count
Definition: disinfect.py:7
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Definition: define.h:272
MSG_TYPE_CARD_ELEGANT_3
#define MSG_TYPE_CARD_ELEGANT_3
Definition: newclient.h:430
artifact_describe
static StringBuffer * artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator)
Definition: readable.cpp:1395
PATH_FROST
#define PATH_FROST
Definition: spells.h:15
archetype
Definition: object.h:474
MSG_TYPE_CARD_MONEY_3
#define MSG_TYPE_CARD_MONEY_3
Definition: newclient.h:436
MSG_TYPE_BOOK_SPELL_EVOKER
#define MSG_TYPE_BOOK_SPELL_EVOKER
Definition: newclient.h:418
ARROW
@ ARROW
Definition: object.h:122
MSG_TYPE_MONUMENT_GRAVESTONE_3
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
Definition: newclient.h:470
living::sp
int16_t sp
Definition: living.h:42
get_message_body
sstring get_message_body(const GeneralMessage *message)
Definition: readable.cpp:2072
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
MSG_TYPE_MONUMENT_STONE_3
#define MSG_TYPE_MONUMENT_STONE_3
Definition: newclient.h:464
MSG_TYPE_MONUMENT_WALL_3
#define MSG_TYPE_MONUMENT_WALL_3
Definition: newclient.h:473
titlelist::number
int number
Definition: readable.cpp:122
BOOK
@ BOOK
Definition: object.h:119
trim
const char * trim(const char *buf)
Definition: readable.cpp:660
MSG_TYPE_PAPER_ENVELOPE_2
#define MSG_TYPE_PAPER_ENVELOPE_2
Definition: newclient.h:447
MSG_TYPE_CARD_ELEGANT_2
#define MSG_TYPE_CARD_ELEGANT_2
Definition: newclient.h:429
MSG_TYPE_PAPER_NOTE_1
#define MSG_TYPE_PAPER_NOTE_1
Definition: newclient.h:439
RING
@ RING
Definition: object.h:190
MSG_TYPE_BOOK_SPELL_SORCERER
#define MSG_TYPE_BOOK_SPELL_SORCERER
Definition: newclient.h:421
MSG_TYPE_BOOK_SPELL_PYRO
#define MSG_TYPE_BOOK_SPELL_PYRO
Definition: newclient.h:420
PATH_TRANSMUTE
#define PATH_TRANSMUTE
Definition: spells.h:27
title::archname
const char * archname
Definition: readable.cpp:111
MSGTYPE_GODS
#define MSGTYPE_GODS
Definition: readable.cpp:89
MSG_TYPE_SIGN_MAGIC_MOUTH
#define MSG_TYPE_SIGN_MAGIC_MOUTH
Definition: newclient.h:459
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
guild_entry.text
text
Definition: guild_entry.py:44
fatal
void fatal(enum fatal_error err)
Definition: utils.cpp:570
mon_desc
static StringBuffer * mon_desc(const object *mon)
Definition: readable.cpp:1297
MAX_BUF
#define MAX_BUF
Definition: define.h:35
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_new
object * object_new(void)
Definition: object.cpp:1273
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Definition: item.cpp:955
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
object::weight
int32_t weight
Definition: object.h:375
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:644
arttypename::type
int type
Definition: readable.cpp:130
StringBuffer
Definition: stringbuffer.cpp:25
PATH_DEATH
#define PATH_DEATH
Definition: spells.h:31
recipe
Definition: recipe.h:10
art_book_name
static const char *const art_book_name[]
Definition: readable.cpp:227
GOD_RESISTANCES
#define GOD_RESISTANCES
Definition: god.h:15
MSG_TYPE_CARD_MONEY_1
#define MSG_TYPE_CARD_MONEY_1
Definition: newclient.h:434
diamondslots.message
string message
Definition: diamondslots.py:57
PATH_TELE
#define PATH_TELE
Definition: spells.h:25
llevInfo
@ llevInfo
Definition: logger.h:12
Floor.t
t
Definition: Floor.py:62
find_archetype_by_object_name
archetype * find_archetype_by_object_name(const char *name)
Definition: arch.cpp:53
MSG_TYPE_PAPER_ENVELOPE_1
#define MSG_TYPE_PAPER_ENVELOPE_1
Definition: newclient.h:446
spells.h
object::name
sstring name
Definition: object.h:319
get_message_title
sstring get_message_title(const GeneralMessage *message)
Definition: readable.cpp:2063
did_first_sp
int did_first_sp
Definition: readable.cpp:1556
MSGTYPE_LIB
#define MSGTYPE_LIB
Definition: readable.cpp:79
MSG_TYPE_CARD_SIMPLE_3
#define MSG_TYPE_CARD_SIMPLE_3
Definition: newclient.h:427
spellpathdef
static const uint32_t spellpathdef[NRSPELLPATHS]
Definition: readable.cpp:149
stringbuffer_delete
void stringbuffer_delete(StringBuffer *sb)
Definition: stringbuffer.cpp:71
msgfile_msg
static StringBuffer * msgfile_msg(object *book, size_t booksize)
Definition: readable.cpp:1768
PATH_PROT
#define PATH_PROT
Definition: spells.h:13
recipe::chance
int chance
Definition: recipe.h:14
artifact::chance
uint16_t chance
Definition: artifact.h:16
MSGTYPE_ALCHEMY
#define MSGTYPE_ALCHEMY
Definition: readable.cpp:87
sstring
const typedef char * sstring
Definition: sstring.h:2
MSG_TYPE_PAPER_LETTER_NEW_1
#define MSG_TYPE_PAPER_LETTER_NEW_1
Definition: newclient.h:444
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:266
MSG_TYPE_BOOK_ELEGANT_2
#define MSG_TYPE_BOOK_ELEGANT_2
Definition: newclient.h:415
strtoint
int strtoint(const char *buf)
Definition: recipe.cpp:709
GOD_ENEMY
#define GOD_ENEMY
Definition: god.h:13
PATH_MIND
#define PATH_MIND
Definition: spells.h:23
object_set_msg
void object_set_msg(object *op, const char *msg)
Definition: object.cpp:4807
recipe::diff
int diff
Definition: recipe.h:16
object::msg
sstring msg
Definition: object.h:330
BOOK_BUF
#define BOOK_BUF
Definition: book.h:16
title::next
title * next
Definition: readable.cpp:115
assets.h
artifactlist::total_chance
uint16_t total_chance
Definition: artifact.h:26
MSGTYPE_ARTIFACT
#define MSGTYPE_ARTIFACT
Definition: readable.cpp:83
npc_dialog.index
int index
Definition: npc_dialog.py:102
do_monster
static void do_monster(archetype *at)
Definition: readable.cpp:873
art_name_array
static const arttypename art_name_array[]
Definition: readable.cpp:207
MSG_TYPE_MONUMENT_STONE_2
#define MSG_TYPE_MONUMENT_STONE_2
Definition: newclient.h:463
stringbuffer_append_stringbuffer
void stringbuffer_append_stringbuffer(StringBuffer *sb, const StringBuffer *sb2)
Definition: stringbuffer.cpp:165
new_text_name
static void new_text_name(object *book, int msgtype)
Definition: readable.cpp:973
heavy_book_name
static const char *const heavy_book_name[]
Definition: readable.cpp:396
level
int level
Definition: readable.cpp:1558
MSGTYPE_SPELLPATH
#define MSGTYPE_SPELLPATH
Definition: readable.cpp:85
readable_message_type
Definition: book.h:36
make_face_from_files.int
int
Definition: make_face_from_files.py:32
formula_author
static const char *const formula_author[]
Definition: readable.cpp:355
booklist
static titlelist * booklist
Definition: readable.cpp:139
MSG_TYPE_MONUMENT_STATUE_1
#define MSG_TYPE_MONUMENT_STATUE_1
Definition: newclient.h:465
title::level
unsigned int level
Definition: readable.cpp:112
MSG_TYPE_MONUMENT_WALL_1
#define MSG_TYPE_MONUMENT_WALL_1
Definition: newclient.h:471
get_readable_message_type
const readable_message_type * get_readable_message_type(object *readable)
Definition: readable.cpp:2050
art_author
static const char *const art_author[]
Definition: readable.cpp:245
last_readable_subtype
static const int last_readable_subtype
Definition: readable.cpp:548
get_random_mon
object * get_random_mon(int level)
Definition: readable.cpp:1268
book_overflow
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
Definition: readable.cpp:718
FOOD
@ FOOD
Definition: object.h:117
MSG_TYPE_PAPER_NOTE_3
#define MSG_TYPE_PAPER_NOTE_3
Definition: newclient.h:441
MSG_TYPE_BOOK_QUARTO_2
#define MSG_TYPE_BOOK_QUARTO_2
Definition: newclient.h:417
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
animate.event
event
DIALOGCHECK MINARGS 1 MAXARGS 2
Definition: animate.py:17
mon_info_msg
static StringBuffer * mon_info_msg(int level, size_t booksize, object *book)
Definition: readable.cpp:1338
unique_book
static int unique_book(const object *book, int msgtype)
Definition: readable.cpp:1070
recipe::ingred
linked_char * ingred
Definition: recipe.h:22
MSG_TYPE_CARD_SIMPLE_1
#define MSG_TYPE_CARD_SIMPLE_1
Definition: newclient.h:425
light_book_name
static const char *const light_book_name[]
Definition: readable.cpp:377
MSG_TYPE_MONUMENT_STONE_1
#define MSG_TYPE_MONUMENT_STONE_1
Definition: newclient.h:462
archetype::name
sstring name
Definition: object.h:475
recipe::next
recipe * next
Definition: recipe.h:24
recipe::skill
sstring skill
Definition: recipe.h:26
living::grace
int16_t grace
Definition: living.h:44
object::stats
living stats
Definition: object.h:378
MSG_TYPE_SIGN
#define MSG_TYPE_SIGN
Definition: newclient.h:387
MSG_TYPE_BOOK
#define MSG_TYPE_BOOK
Definition: newclient.h:384
artifact
Definition: artifact.h:14
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.cpp:4495
buf_overflow
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
Definition: shstr.cpp:398
describe_god
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Definition: holy.cpp:109
add_book
static void add_book(title *book, int type, const char *fname, int lineno)
Definition: readable.cpp:859
MSG_TYPE_PAPER_SCROLL_MAGIC
#define MSG_TYPE_PAPER_SCROLL_MAGIC
Definition: newclient.h:452
BOOTS
@ BOOTS
Definition: object.h:217
make_formula_book
static void make_formula_book(object *book, int level)
Definition: readable.cpp:1637
FLAG_CHANGING
#define FLAG_CHANGING
Definition: define.h:263
title::msg_index
int msg_index
Definition: readable.cpp:114
SPELL
@ SPELL
Definition: object.h:219
MSG_TYPE_PAPER_SCROLL_NEW_1
#define MSG_TYPE_PAPER_SCROLL_NEW_1
Definition: newclient.h:450
sp_params
static struct @0 sp_params
SHIELD
@ SHIELD
Definition: object.h:140
OUT_OF_MEMORY
@ OUT_OF_MEMORY
Definition: define.h:48
BOOKSIZE
#define BOOKSIZE(xyz)
Definition: book.h:31
max_titles
static const int max_titles[6]
Definition: readable.cpp:551
nstrtok
int nstrtok(const char *buf1, const char *buf2)
Definition: readable.cpp:641
living.h
find_artifactlist
artifactlist * find_artifactlist(int type)
Definition: artifact.cpp:574
artifactlist::type
uint8_t type
Definition: artifact.h:25
MSG_TYPE_CARD_STRANGE_3
#define MSG_TYPE_CARD_STRANGE_3
Definition: newclient.h:433
get_message_face
const Face * get_message_face(const GeneralMessage *message)
Definition: readable.cpp:2081
pnum
uint32_t pnum
Definition: readable.cpp:1557
recipe_get_difficulty_string
const char * recipe_get_difficulty_string(int difficulty)
Definition: recipe.cpp:962
llevDebug
@ llevDebug
Definition: logger.h:13
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
GOD_SACRED
#define GOD_SACRED
Definition: god.h:16
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
give.name
name
Definition: give.py:27
OutputFile
Definition: output_file.h:41
recipe::cauldron
sstring cauldron
Definition: recipe.h:27
recipe::title
sstring title
Definition: recipe.h:11
level
Definition: level.py:1
Settings::localdir
const char * localdir
Definition: global.h:249