Crossfire Server, Trunk  R20513
readable.c
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 
38 /* Define this if you want to archive book titles by contents.
39  * This option should enforce UNIQUE combinations of titles,authors and
40  * msg contents during and *between *game sessions.
41  * Note: a slight degeneracy exists since books are archived based on an integer
42  * index value calculated from the message text (similar to alchemy formulae).
43  * Sometimes two widely different messages have the same index value (rare). In
44  * this case, it is possible to occasionally generate 2 books with same title and
45  * different message content. Not really a bug, but rather a feature. This action
46  * should keeps player on their toes ;).
47  * Also, note that there is *finite *space available for archiving message and titles.
48  * Once this space is used, books will stop being archived. Not a serious problem
49  * under the current regime, since there are generally fewer possible (random)
50  * messages than space available on the titlelists.
51  * One exception (for sure) are the monster messages. But no worries, you should
52  * see all of the monster info in some order (but not all possble combinations)
53  * before the monster titlelist space is run out. You can increase titlelist
54  * space by increasing the array sizes for the monster book_authours and book_names
55  * (see max_titles[] array and include/read.h). Since the unique_book algorthm is
56  * kinda stupid, this program *may *slow down program execution if defined (but I don't
57  * think its a significant problem, at least, I have no problems running this option
58  * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg
59  * combinations have been generated, unique_book isnt called anymore. It takes 5-10
60  * sessions for this to happen).
61  * Final note: the game remembers book/title/msg combinations from reading the
62  * file lib/bookarch. If you REMOVE this file, you will lose your archive. So
63  * be sure to copy it over to the new lib directory when you change versions.
64  * -b.t.
65  */
66 
67 /* This flag is useful to see what kind of output messages are created */
68 /* #define BOOK_MSG_DEBUG */
69 
70 /* This flag is useful for debugging archiving action */
71 /* #define ARCHIVE_DEBUG */
72 
74 #define MAX_TITLE_CHECK 20
75 
77 #define MSGTYPE_LIB 0
78 
79 #define MSGTYPE_MONSTER 1
80 
81 #define MSGTYPE_ARTIFACT 2
82 
83 #define MSGTYPE_SPELLPATH 3
84 
85 #define MSGTYPE_ALCHEMY 4
86 
87 #define MSGTYPE_GODS 5
88 
89 #define MSGTYPE_MSGFILE 6
90 
96 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
97 
98 /* Moved these structures from struct.h to this file in 0.94.3 - they
99  * are not needed anyplace else, so why have them globally declared?
100  */
101 
106 typedef struct titlestruct {
107  const char *name;
108  const char *authour;
109  const char *archname;
110  unsigned int level;
111  size_t size;
112  int msg_index;
113  struct titlestruct *next;
114 } title;
115 
119 typedef struct titleliststruct {
120  int number;
123 } titlelist;
124 
126 typedef struct namebytype {
127  const char *name;
128  int type;
129 } arttypename;
130 
135  int chance;
141  unsigned int face;
143 };
144 
145 static void add_book(title *book, int type, const char *fname, int lineno);
146 
151 static titlelist *booklist = NULL;
152 
154 static objectlink *first_mon_info = NULL;
155 
156 static int nrofmon = 0,
164 static GeneralMessage *first_msg = NULL;
165 
169 static int msg_total_chance = 0;
170 
175  PATH_PROT,
176  PATH_FIRE,
177  PATH_FROST,
178  PATH_ELEC,
179  PATH_MISSILE,
180  PATH_SELF,
181  PATH_SUMMON,
182  PATH_ABJURE,
183  PATH_RESTORE,
185  PATH_MIND,
186  PATH_CREATE,
187  PATH_TELE,
188  PATH_INFO,
191  PATH_TURNING,
193  PATH_DEATH,
194  PATH_LIGHT
195 };
196 
198 static const char *const path_book_name[] = {
199  "codex",
200  "compendium",
201  "exposition",
202  "tables",
203  "treatise"
204 };
205 
207 static const char *const path_author[] = {
208  "aether",
209  "astral byways",
210  "connections",
211  "the Grey Council",
212  "deep pathways",
213  "knowledge",
214  "magic",
215  "mystic ways",
216  "pathways",
217  "power",
218  "spells",
219  "transforms",
220  "the mystic veil",
221  "unknown spells"
222 };
223 
230 static const arttypename art_name_array[] = {
231  { "Helmet", HELMET },
232  { "Amulet", AMULET },
233  { "Shield", SHIELD },
234  { "Bracers", BRACERS },
235  { "Boots", BOOTS },
236  { "Cloak", CLOAK },
237  { "Gloves", GLOVES },
238  { "Gridle", GIRDLE },
239  { "Ring", RING },
240  { "Horn", ROD },
241  { "Missile Weapon", BOW },
242  { "Missile", ARROW },
243  { "Hand Weapon", WEAPON },
244  { "Artifact", SKILL },
245  { "Food", FOOD },
246  { "Body Armour", ARMOUR }
247 };
248 
250 static const char *const art_book_name[] = {
251  "collection",
252  "file",
253  "files",
254  "guide",
255  "handbook",
256  "index",
257  "inventory",
258  "list",
259  "listing",
260  "record",
261  "record book"
262 };
263 
265 static const char *const art_author[] = {
266  "ancient things",
267  "artifacts",
268  "Havlor", /* ancient warrior scribe :) */
269  "items",
270  "lost artifacts",
271  "the ancients",
272  "useful things"
273 };
274 
278 static const char *const mon_book_name[] = {
279  "beastuary",
280  "catalog",
281  "compilation",
282  "collection",
283  "encyclopedia",
284  "guide",
285  "handbook",
286  "list",
287  "manual",
288  "notes",
289  "record",
290  "register",
291  "volume"
292 };
293 
295 static const char *const mon_author[] = {
296  "beasts",
297  "creatures",
298  "dezidens",
299  "dwellers",
300  "evil nature",
301  "life",
302  "monsters",
303  "nature",
304  "new life",
305  "residents",
306  "the spawn",
307  "the living",
308  "things"
309 };
310 
314 static const char *const gods_book_name[] = {
315  "devotional",
316  "devout notes",
317  "divine text",
318  "divine work",
319  "holy book",
320  "holy record",
321  "moral text",
322  "sacred guide",
323  "testament",
324  "transcript"
325 };
326 
328 static const char *const gods_author[] = {
329  "cults",
330  "joy",
331  "lasting curse",
332  "madness",
333  "religions",
334  "the dead",
335  "the gods",
336  "the heirophant",
337  "the poor priest",
338  "the priestess",
339  "pain",
340  "white"
341 };
342 
346 static const char *const formula_book_name[] = {
347  "cookbook",
348  "formulary",
349  "lab book",
350  "lab notes",
351  "recipe book",
352  "experiment record",
353  "work plan",
354  "design notes"
355 };
356 
358 static const char *const formula_author[] = {
359  "Albertus Magnus",
360  "alchemy",
361  "balms",
362  "creation",
363  "dusts",
364  "magical manufacture",
365  "making",
366  "philosophical items",
367  "potions",
368  "powders",
369  "the cauldron",
370  "the lamp black",
371  "transmutation",
372  "waters"
373 };
374 
380 static const char *const light_book_name[] = {
381  "calendar",
382  "datebook",
383  "diary",
384  "guidebook",
385  "handbook",
386  "ledger",
387  "notes",
388  "notebook",
389  "octavo",
390  "pamphlet",
391  "practicum",
392  "script",
393  "transcript"
394 };
395 
397 static const char *const heavy_book_name[] = {
398  "catalog",
399  "compendium",
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  "Magnuson",
436  "Nandii",
437  "Nitfeder",
438  "Norris",
439  "Parael",
440  "Penhew",
441  "Sophia",
442  "Skilly",
443  "Tahir",
444  "Thockmorton",
445  "Thomas",
446  "van Helsing",
447  "van Pelt",
448  "Voormis",
449  "Xavier",
450  "Xeno",
451  "Zardoz",
452  "Zagy"
453 };
454 
456 static const char *const book_descrpt[] = {
457  "ancient",
458  "cryptic",
459  "cryptical",
460  "dusty",
461  "hiearchical",
462  "grizzled",
463  "gold-guilt",
464  "great",
465  "lost",
466  "magnificent",
467  "musty",
468  "mythical",
469  "mystical",
470  "rustic",
471  "stained",
472  "silvered",
473  "transcendental",
474  "weathered"
475 };
476 
484  /*subtype 0 */ { 0, 0 },
485  /* book messages subtypes */
486  /*subtype 1 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1 },
495  /*subtype 10 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER },
497  /* card messages subtypes*/
506  /*subtype 20 */ { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3 },
510  /* Paper messages subtypes */
517  /*subtype 30 */ { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2 },
525  /* road signs messages subtypes */
528  /*subtype 40 */ { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT },
530  /* stones and monument messages */
544 };
545 
547 static const int last_readable_subtype = arraysize(readable_message_types);
548 
550 static const int max_titles[6] = {
552  arraysize(mon_book_name)*arraysize(mon_author), /* MSGTYPE_MONSTER */
553  arraysize(art_book_name)*arraysize(art_author), /* MSGTYPE_ARTIFACT */
554  arraysize(path_book_name)*arraysize(path_author), /* MSGTYPE_SPELLPATH */
555  arraysize(formula_book_name)*arraysize(formula_author), /* MSGTYPE_ALCHEMY */
556  arraysize(gods_book_name)*arraysize(gods_author), /* MSGTYPE_GODS */
557 };
558 
559 /******************************************************************************
560  *
561  * Start of misc. readable functions used by others functions in this file
562  *
563  *****************************************************************************/
564 
575  titlelist *bl = (titlelist *)malloc(sizeof(titlelist));
576 
577  if (bl == NULL)
579  bl->number = 0;
580  bl->first_book = NULL;
581  bl->next = NULL;
582  return bl;
583 }
584 
594 static title *get_empty_book(void) {
595  title *t = (title *)malloc(sizeof(title));
596 
597  if (t == NULL)
599  t->name = NULL;
600  t->archname = NULL;
601  t->authour = NULL;
602  t->level = 0;
603  t->size = 0;
604  t->msg_index = 0;
605  t->next = NULL;
606  return t;
607 }
608 
619 static titlelist *get_titlelist(int i) {
620  titlelist *tl;
621  int number;
622 
623  if (i < 0 || i >= (int)arraysize(max_titles)) {
624  LOG(llevInfo, "Warning: invalid book index %d, using 0 instead\n", i);
625  return booklist;
626  }
627 
628  for (tl = booklist, number = i; tl && number; tl = tl->next, number--) {
629  if (!tl->next)
630  tl->next = get_empty_booklist();
631  }
632 
633  return tl;
634 }
635 
636 /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file
637  * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
638 
650 int nstrtok(const char *buf1, const char *buf2) {
651  char *tbuf, buf[MAX_BUF];
652  int number = 0;
653 
654  if (!buf1 || !buf2)
655  return 0;
656 
657  snprintf(buf, sizeof(buf), "%s", buf1);
658  for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
659  number++;
660  }
661  return number;
662 }
663 
680 char *strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size) {
681  int maxi, i = nstrtok(buf1, buf2);
682  char *tbuf, buf[MAX_BUF];
683 
684  maxi = i;
685  snprintf(buf, sizeof(buf), "%s", buf1);
686  snprintf(retbuf, size, " ");
687  for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
688  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "%s", tbuf);
689  i--;
690  if (i == 1 && maxi > 1)
691  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), " and ");
692  else if (i > 0 && maxi > 1)
693  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ", ");
694  else
695  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ".");
696  }
697  return retbuf;
698 }
699 
710 int book_overflow(const char *buf1, const char *buf2, size_t booksize) {
711  if (buf_overflow(buf1, buf2, BOOK_BUF-2) /* 2 less so always room for trailing \n */
712  || buf_overflow(buf1, buf2, booksize))
713  return 1;
714  return 0;
715 }
716 
717 /*****************************************************************************
718  *
719  * Start of initialization related functions.
720  *
721  ****************************************************************************/
722 
728 static void init_msgfile(void) {
729  FILE *fp;
730  char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp;
731  int text = 0, nrofmsg = 0;
732  static int did_init_msgfile = 0;
733 
734  if (did_init_msgfile)
735  return;
736  did_init_msgfile = 1;
737 
738  snprintf(fname, sizeof(fname), "%s/messages", settings.datadir);
739  LOG(llevDebug, "Reading messages from %s...\n", fname);
740 
741  fp = fopen(fname, "r");
742  if (fp != NULL) {
743  GeneralMessage *tmp = NULL;
744  int lineno;
745  int error_lineno;
746 
747  error_lineno = 0;
748  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
749  if (*buf == '#')
750  continue;
751  cp = strchr(buf, '\n');
752  if (cp != NULL) {
753  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
754  cp--;
755  *cp = '\0';
756  }
757  if (tmp != NULL) {
758  if (text && strcmp(buf, "ENDMSG") == 0) {
759  if (strlen(msgbuf) > BOOK_BUF) {
760  LOG(llevDebug, "Warning: this string exceeded max book buf size:\n");
761  LOG(llevDebug, " %s\n", msgbuf);
762  }
763  tmp->message = add_string(msgbuf);
764  tmp->next = first_msg;
765  first_msg = tmp;
766  nrofmsg++;
767  if (tmp->identifier != NULL && tmp->title == NULL) {
768  LOG(llevError, "Error: message can't have identifier without title, on line %d\n", error_lineno);
770  }
771  tmp = NULL;
772  text = 0;
773  } else if (text) {
774  if (!buf_overflow(msgbuf, buf, HUGE_BUF-1)) {
775  strcat(msgbuf, buf);
776  strcat(msgbuf, "\n");
777  } else if (error_lineno != 0) {
778  LOG(llevInfo, "Warning: truncating book at %s, line %d\n", fname, error_lineno);
779  }
780  } else if (strcmp(buf, "TEXT") == 0) {
781  text = 1;
782  } else if (strncmp(buf, "CHANCE ", 7) == 0) {
783  tmp->chance = atoi(buf + 7);
784  msg_total_chance += tmp->chance;
785  } else if (strncmp(buf, "TITLE ", 6) == 0) {
786  tmp->title = add_string(buf + 6);
787  } else if (strncmp(buf, "QUEST ", 6) == 0) {
788  tmp->quest_code = add_string(buf + 6);
789  } else if (strncmp(buf, "FACE ", 5) == 0) {
790  unsigned int face = find_face(buf + 5, (unsigned int)-1);
791  if (face != (unsigned int)-1) {
792  tmp->face = face;
793  } else {
794  LOG(llevInfo, "Warning: unknown face %s for message %s, line %d\n", buf + 5, tmp->identifier, error_lineno);
795  }
796  } else if (error_lineno != 0) {
797  LOG(llevInfo, "Warning: unknown line %s, line %d\n", buf, error_lineno);
798  }
799  } else if (strncmp(buf, "MSG", 3) == 0) {
800  error_lineno = lineno;
801  tmp = (GeneralMessage *)calloc(1, sizeof(GeneralMessage));
802  tmp->face = -1;
803  strcpy(msgbuf, " "); /* reset msgbuf for new message */
804  if (buf[3] == ' ') {
805  int i = 4;
806  while (buf[i] == ' ' && buf[i] != '\0')
807  i++;
808  if (buf[i] != '\0') {
809  tmp->identifier = add_string(buf + i);
810  if (get_message_from_identifier(buf + i)) {
811  LOG(llevError, "Duplicated message identifier %s at line %d\n", buf + i, error_lineno);
813  }
814  }
815  }
816  } else {
817  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
818  }
819  }
820  fclose(fp);
821 
822  if (tmp != NULL) {
823  LOG(llevError, "Invalid file %s", fname);
825  }
826  }
827 
828  LOG(llevDebug, "done messages, found %d for total chance %d.\n", nrofmsg, msg_total_chance);
829 }
830 
837 static void init_book_archive(void) {
838  FILE *fp;
839  int nroftitle = 0;
840  char buf[MAX_BUF], fname[MAX_BUF], *cp;
841  static int did_init_barch = 0;
842 
843  if (did_init_barch)
844  return;
845  did_init_barch = 1;
846 
847  if (!booklist)
848  booklist = get_empty_booklist();
849 
850  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
851  LOG(llevDebug, " Reading bookarch from %s...\n", fname);
852 
853  fp = fopen(fname, "r");
854  if (fp != NULL) {
855  int type;
856  size_t i;
857  titlelist *bl;
858  int lineno;
859  title *book;
860  int skipping;
861 
862  skipping = 0;
863  book = NULL;
864  type = -1;
865  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
866  int len;
867  int value;
868 
869  if (*buf == '#')
870  continue;
871  cp = strchr(buf, '\n');
872  if (cp != NULL) {
873  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
874  cp--;
875  *cp = '\0';
876  }
877  cp = buf;
878  if (strncmp(buf, "title ", 6) == 0) {
879  skipping = 0;
880  cp = buf+6;
881  while (*cp == ' ' || *cp == '\t')
882  cp++;
883  if (*cp == '\0') {
884  LOG(llevInfo, "Warning: missing book title at %s, line %d\n", fname, lineno);
885  book = NULL;
886  } else {
887  book = get_empty_book(); /* init new book entry */
888  book->name = add_string(cp);
889  type = -1;
890  nroftitle++;
891  }
892  } else if (book == NULL) {
893  if (!skipping) {
894  skipping = 1;
895  LOG(llevInfo, "Warning: expecting 'title' at %s, line %d\n", fname, lineno);
896  }
897  } else if (strncmp(buf, "authour ", 8) == 0) {
898  cp = buf+8;
899  while (*cp == ' ' || *cp == '\t')
900  cp++;
901  if (*cp == '\0') {
902  LOG(llevInfo, "Warning: missing book authour at %s, line %d\n", fname, lineno);
903  } else {
904  book->authour = add_string(cp);
905  }
906  } else if (strncmp(buf, "arch ", 5) == 0) {
907  cp = buf+5;
908  while (*cp == ' ' || *cp == '\t')
909  cp++;
910  if (*cp == '\0') {
911  LOG(llevInfo, "Warning: missing book arch at %s, line %d\n", fname, lineno);
912  } else {
913  book->archname = add_string(cp);
914  }
915  } else if (sscanf(buf, "level %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
916  book->level = value;
917  } else if (sscanf(buf, "type %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
918  type = value;
919  } else if (sscanf(buf, "size %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
920  book->size = value;
921  } else if (sscanf(buf, "index %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
922  book->msg_index = value;
923  } else if (strcmp(buf, "end") == 0) { /* link it */
924  add_book(book, type, fname, lineno);
925  book = NULL;
926  type = -1;
927  } else {
928  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
929  }
930  }
931  if (book != NULL) {
932  LOG(llevInfo, "Warning: missing 'end' at %s, line %d\n", fname, lineno);
933  add_book(book, type, fname, lineno);
934  }
935  LOG(llevDebug, " book archives(used/avail):\n");
936  for (bl = booklist, i = 0; bl != NULL && i < arraysize(max_titles); bl = bl->next, i++) {
937  LOG(llevDebug, "(%d/%d)\n", bl->number, max_titles[i]);
938  }
939  fclose(fp);
940  }
941 
942 #ifdef BOOK_MSG_DEBUG
943  LOG(llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle);
944 #endif
945  LOG(llevDebug, " done.\n");
946 }
947 
955 static void add_book(title *book, int type, const char *fname, int lineno) {
956  titlelist *bl;
957 
958  if (type == -1) {
959  LOG(llevInfo, "Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
960  type = 0;
961  }
962 
963  bl = get_titlelist(type);
964  book->next = bl->first_book;
965  bl->first_book = book;
966  bl->number++;
967 }
968 
973 static void init_mon_info(void) {
974  archetype *at;
975  static int did_init_mon_info = 0;
976 
977  if (did_init_mon_info)
978  return;
979  did_init_mon_info = 1;
980 
981  for (at = first_archetype; at != NULL; at = at->next) {
982  if (QUERY_FLAG(&at->clone, FLAG_MONSTER)
984  objectlink *mon = (objectlink *)malloc(sizeof(objectlink));
985  if (!mon) {
986  LOG(llevError, "init_mon_info: malloc failed!\n");
987  abort();
988  }
989  mon->ob = &at->clone;
990  mon->id = nrofmon;
991  mon->next = first_mon_info;
992  first_mon_info = mon;
993  nrofmon++;
994  }
995  }
996  LOG(llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
997 }
998 
1005 void init_readable(void) {
1006  static int did_this = 0;
1007 
1008  if (did_this)
1009  return;
1010  did_this = 1;
1011 
1012  LOG(llevDebug, "Initializing reading data...\n");
1013  init_msgfile();
1015  init_mon_info();
1016  LOG(llevDebug, " done reading data\n");
1017 }
1018 
1019 /*****************************************************************************
1020  *
1021  * This is the start of the administrative functions when creating
1022  * new books (ie, updating title and the like)
1023  *
1024  *****************************************************************************/
1025 
1037 static title *find_title(const object *book, int msgtype) {
1038  title *t;
1039  titlelist *tl;
1040  size_t length;
1041  int index;
1042 
1043  if (msgtype < 0)
1044  return (title *)NULL;
1045 
1046  tl = get_titlelist(msgtype);
1047  if (!tl)
1048  return (title *)NULL;
1049 
1050  length = strlen(book->msg);
1051  index = strtoint(book->msg);
1052  for (t = tl->first_book; t; t = t->next)
1053  if (t->size == length && t->msg_index == index) {
1054 #ifdef ARCHIVE_DEBUG
1055  LOG(llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
1056 #endif
1057  return t;
1058  }
1059 
1060  return (title *)NULL;
1061 }
1062 
1076 static void new_text_name(object *book, int msgtype) {
1077  const char *name;
1078 
1079  if (book->type != BOOK)
1080  return;
1081 
1082  switch (msgtype) {
1083  case MSGTYPE_MONSTER:
1085  break;
1086 
1087  case MSGTYPE_ARTIFACT:
1089  break;
1090 
1091  case MSGTYPE_SPELLPATH:
1093  break;
1094 
1095  case MSGTYPE_ALCHEMY:
1097  break;
1098 
1099  case MSGTYPE_GODS:
1101  break;
1102 
1103  case MSGTYPE_MSGFILE:
1104  default:
1105  if (book->weight > 2000) { /* based on weight */
1107  } else {
1109  }
1110  break;
1111  }
1112  free_string(book->name);
1113  book->name = add_string(name);
1114 }
1115 
1125 static void add_author(object *op, int msgtype) {
1126  char title[MAX_BUF];
1127  const char *name;
1128 
1129  if (msgtype < 0 || strlen(op->msg) < 5)
1130  return;
1131 
1132  switch (msgtype) {
1133  case MSGTYPE_MONSTER:
1135  break;
1136 
1137  case MSGTYPE_ARTIFACT:
1139  break;
1140 
1141  case MSGTYPE_SPELLPATH:
1143  break;
1144 
1145  case MSGTYPE_ALCHEMY:
1147  break;
1148 
1149  case MSGTYPE_GODS:
1151  break;
1152 
1153  case MSGTYPE_MSGFILE:
1154  default:
1156  }
1157 
1158  snprintf(title, sizeof(title), "of %s", name);
1159  op->title = add_string(title);
1160 }
1161 
1173 static int unique_book(const object *book, int msgtype) {
1174  title *test;
1175 
1176  if (!booklist)
1177  return 1; /* No archival entries! Must be unique! */
1178 
1179  /* Go through the booklist. If the author and name match, not unique so
1180  * return 0.
1181  */
1182  for (test = get_titlelist(msgtype)->first_book; test; test = test->next) {
1183  if (!strcmp(test->name, book->name) && !strcmp(book->title, test->authour))
1184  return 0;
1185  }
1186  return 1;
1187 }
1188 
1197 static void add_book_to_list(const object *book, int msgtype) {
1198  titlelist *tl = get_titlelist(msgtype);
1199  title *t;
1200 
1201  if (!tl) {
1202  LOG(llevError, "add_book_to_list can't get booklist!\n");
1203  return;
1204  }
1205 
1206  t = get_empty_book();
1207  t->name = add_string(book->name);
1208  t->authour = add_string(book->title);
1209  t->size = strlen(book->msg);
1210  t->msg_index = strtoint(book->msg);
1211  t->archname = add_string(book->arch->name);
1212  t->level = book->level;
1213 
1214  t->next = tl->first_book;
1215  tl->first_book = t;
1216  tl->number++;
1217 
1218  /* We have stuff we need to write now */
1220 
1221 #ifdef ARCHIVE_DEBUG
1222  LOG(llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
1223 #endif
1224 }
1225 
1239 static void change_book(object *book, int msgtype) {
1240  titlelist *tl;
1241  title *t;
1242  int tries;
1243 
1244  if (book->type != BOOK) {
1245  LOG(llevError, "change_book_name() called w/ illegal obj type.\n");
1246  return;
1247  }
1248 
1249  tl = get_titlelist(msgtype);
1250  t = NULL;
1251  tries = 0;
1252 
1253  /* look to see if our msg already been archived. If so, alter
1254  * the book to match the archival text. If we fail to match,
1255  * then we archive the new title/name/msg combo if there is
1256  * room on the titlelist.
1257  */
1258 
1259  if (strlen(book->msg) > 5 && (t = find_title(book, msgtype))) {
1260  object *tmpbook;
1261  sstring marker = object_get_value(book, "knowledge_marker");
1262 
1263  /* alter book properties */
1264  tmpbook = create_archetype(t->archname);
1265  if (marker != NULL)
1266  /* need to copy the knowledge_marker */
1267  object_set_value(tmpbook, "knowledge_marker", marker, 1);
1268  object_set_msg(tmpbook, book->msg);
1269  object_copy(tmpbook, book);
1270  object_free_drop_inventory(tmpbook);
1271 
1272  book->title = add_string(t->authour);
1273  free_string(book->name);
1274  book->name = add_string(t->name);
1275  book->level = t->level;
1276  } else { /* Don't have any default title, so lets make up a new one */
1277  int numb, maxnames = max_titles[msgtype];
1278  const char *old_title;
1279  const char *old_name;
1280 
1281  old_title = book->title ? add_string(book->title) : NULL;
1282  old_name = add_string(book->name);
1283 
1284  /* some pre-generated books have title already set (from
1285  * maps), also don't bother looking for unique title if
1286  * we already used up all the available names! */
1287 
1288  if (!tl) {
1289  LOG(llevError, "change_book_name(): can't find title list\n");
1290  numb = 0;
1291  } else
1292  numb = tl->number;
1293 
1294  if (numb == maxnames) {
1295 #ifdef ARCHIVE_DEBUG
1296  LOG(llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1297 #endif
1298  if (old_title != NULL)
1299  free_string(old_title);
1300  free_string(old_name);
1301  return;
1302  }
1303  /* shouldnt change map-maker books */
1304  if (!book->title)
1305  do {
1306  /* random book name */
1307  new_text_name(book, msgtype);
1308  add_author(book, msgtype); /* random author */
1309  tries++;
1310  } while (!unique_book(book, msgtype) && tries < MAX_TITLE_CHECK);
1311 
1312  /* Now deal with 2 cases.
1313  * 1) If no space for a new title exists lets just restore
1314  * the old book properties. Remember, if the book had
1315  * matchd an older entry on the titlelist, we shouldnt
1316  * have called this routine in the first place!
1317  * 2) If we got a unique title, we need to add it to
1318  * the list.
1319  */
1320 
1321  if (tries == MAX_TITLE_CHECK) {
1322 #ifdef ARCHIVE_DEBUG
1323  LOG(llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1324 #endif
1325  /* restore old book properties here */
1326  free_string(book->name);
1327  free_string(book->title);
1328  book->title = old_title != NULL ? add_string(old_title) : NULL;
1329 
1330  if (RANDOM()%4) {
1331  /* Lets give the book a description to individualize it some */
1332  char new_name[MAX_BUF];
1333 
1334  snprintf(new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM()%arraysize(book_descrpt)], old_name);
1335  book->name = add_string(new_name);
1336  } else {
1337  book->name = add_string(old_name);
1338  }
1339  } else if (book->title && strlen(book->msg) > 5) { /* archive if long msg texts */
1340  add_book_to_list(book, msgtype);
1341  }
1342 
1343  if (old_title != NULL)
1344  free_string(old_title);
1345  free_string(old_name);
1346  }
1347 }
1348 
1349 /*****************************************************************************
1350  *
1351  * This is the start of the area that generates the actual contents
1352  * of the book.
1353  *
1354  *****************************************************************************/
1355 
1356 /*****************************************************************************
1357  * Monster msg generation code.
1358  ****************************************************************************/
1359 
1371 object *get_random_mon(int level) {
1372  objectlink *mon;
1373  int i, monnr;
1374 
1375  /* safety check. Problem w/ init_mon_info list? */
1376  if (!nrofmon || !first_mon_info)
1377  return (object *)NULL;
1378 
1379  if (!level) {
1380  /* lets get a random monster from the mon_info linked list */
1381  monnr = RANDOM()%nrofmon;
1382 
1383  for (mon = first_mon_info, i = 0; mon; mon = mon->next, i++)
1384  if (i == monnr)
1385  break;
1386 
1387  if (!mon) {
1388  LOG(llevError, "get_random_mon: Didn't find a monster when we should have\n");
1389  return NULL;
1390  }
1391  return mon->ob;
1392  }
1393 
1394  /* Case where we are searching by level. Redone 971225 to be clearer
1395  * and more random. Before, it looks like it took a random monster from
1396  * the list, and then returned the first monster after that which was
1397  * appropriate level. This wasn't very random because if you had a
1398  * bunch of low level monsters and then a high level one, if the random
1399  * determine took one of the low level ones, it would just forward to the
1400  * high level one and return that. Thus, monsters that immediately followed
1401  * a bunch of low level monsters would be more heavily returned. It also
1402  * means some of the dragons would be poorly represented, since they
1403  * are a group of high level monsters all around each other.
1404  */
1405 
1406  /* First count number of monsters meeting level criteria */
1407  for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1408  if (mon->ob->level >= level)
1409  i++;
1410 
1411  if (i == 0) {
1412  LOG(llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1413  return NULL;
1414  }
1415 
1416  monnr = RANDOM()%i;
1417  for (mon = first_mon_info; mon; mon = mon->next)
1418  if (mon->ob->level >= level && monnr-- == 0)
1419  return mon->ob;
1420 
1421  LOG(llevError, "get_random_mon(): didn't find a monster when we should have\n");
1422  return NULL;
1423 }
1424 
1434 static StringBuffer *mon_desc(const object *mon) {
1435  StringBuffer *desc = stringbuffer_new();
1436  stringbuffer_append_printf(desc, "\n---\n *** %s ***\n", mon->name);
1437  describe_item(mon, NULL, 0, desc);
1438  return desc;
1439 }
1440 
1452 static object *get_next_mon(const object *tmp) {
1453  objectlink *mon;
1454 
1455  for (mon = first_mon_info; mon; mon = mon->next)
1456  if (mon->ob == tmp)
1457  break;
1458 
1459  /* didn't find a match */
1460  if (!mon)
1461  return NULL;
1462  if (mon->next)
1463  return mon->next->ob;
1464  else
1465  return first_mon_info->ob;
1466 }
1467 
1480 static StringBuffer *mon_info_msg(int level, size_t booksize, object *book) {
1481  object *tmp;
1482  StringBuffer *marker = stringbuffer_new(), *desc = stringbuffer_new(), *mon = NULL;
1483  int added = 0;
1484  sstring final;
1485 
1486  /*preamble */
1487  stringbuffer_append_string(desc, "This beastiary contains:");
1488  stringbuffer_append_string(marker, "monster");
1489 
1490  /* lets print info on as many monsters as will fit in our
1491  * document.
1492  * 8-96 Had to change this a bit, otherwise there would
1493  * have been an impossibly large number of combinations
1494  * of text! (and flood out the available number of titles
1495  * in the archive in a snap!) -b.t.
1496  */
1497  for (tmp = get_random_mon(level*3); tmp; tmp = get_next_mon(tmp)) {
1498  /* monster description */
1499  mon = mon_desc(tmp);
1500 
1501  if (stringbuffer_length(desc) + stringbuffer_length(mon) >= booksize)
1502  break;
1503  added++;
1504  stringbuffer_append_printf(marker, ":%s", tmp->arch->name);
1507  mon = NULL;
1508  }
1509 
1510  if (mon != NULL) {
1512  }
1513 
1514  final = stringbuffer_finish_shared(marker);
1515  if (added)
1516  object_set_value(book, "knowledge_marker", final, 1);
1517  free_string(final);
1518 
1519  return desc;
1520 }
1521 
1522 /*****************************************************************************
1523  * Artifact msg generation code.
1524  ****************************************************************************/
1525 
1535 static StringBuffer *artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator) {
1536  object *tmp;
1537  int chance;
1538  StringBuffer *desc = stringbuffer_new(), *sbuf;
1539 
1540  if (separator)
1541  stringbuffer_append_string(desc, "---\n");
1542 
1543  /* Name */
1544  if (art->allowed != NULL) {
1545  archetype *arch;
1546  linked_char *temp = art->allowed;
1547  int inv = 0, w;
1548 
1549  assert(art->allowed_size > 0);
1550  if (art->allowed_size > 1)
1551  w = 1 + RANDOM() % art->allowed_size;
1552  else
1553  w = 1;
1554 
1555  while (w > 1) {
1556  assert(temp);
1557  temp = temp->next;
1558  w--;
1559  }
1560 
1561  if (temp->name[0] == '!')
1562  inv = 1;
1563 
1565  arch = try_find_archetype(temp->name + inv);
1566  if (!arch)
1567  arch = find_archetype_by_object_name(temp->name + inv);
1568 
1569  if (!arch)
1570  LOG(llevError, "artifact_msg: missing archetype %s for artifact %s (type %d)\n", temp->name + inv, art->item->name, art->item->type);
1571  else {
1572  if (inv)
1573  stringbuffer_append_printf(desc, " A %s (excepted %s) of %s", art_name_array[art_name].name, arch->clone.name_pl, art->item->name);
1574  else
1575  stringbuffer_append_printf(desc, " A %s of %s", arch->clone.name, art->item->name);
1576  }
1577  } else { /* default name is used */
1578  /* use the base 'generic' name for our artifact */
1579  stringbuffer_append_printf(desc, " The %s of %s", art_name_array[art_name].name, art->item->name);
1580  }
1581 
1582  /* chance of finding */
1583  stringbuffer_append_string(desc, " is ");
1584  chance = 100*((float)art->chance/al->total_chance);
1585  if (chance >= 20)
1586  stringbuffer_append_string(desc, "an uncommon");
1587  else if (chance >= 10)
1588  stringbuffer_append_string(desc, "an unusual");
1589  else if (chance >= 5)
1590  stringbuffer_append_string(desc, "a rare");
1591  else
1592  stringbuffer_append_string(desc, "a very rare");
1593 
1594  /* value of artifact */
1595  stringbuffer_append_printf(desc, " item with a value that is %d times normal.\n", art->item->value);
1596 
1597  /* include the message about the artifact, if exists, and book
1598  * level is kinda high */
1599  if (message && !(strlen(art->item->msg) > BOOK_BUF))
1600  stringbuffer_append_string(desc, art->item->msg);
1601 
1602  /* properties of the artifact */
1603  tmp = object_new();
1604  add_abilities(tmp, art->item);
1605  tmp->type = al->type;
1606  SET_FLAG(tmp, FLAG_IDENTIFIED);
1607  sbuf = describe_item(tmp, NULL, 0, NULL);
1608  if (stringbuffer_length(sbuf) > 1) {
1609  stringbuffer_append_string(desc, " Properties of this artifact include:\n ");
1611  stringbuffer_append_string(desc, "\n");
1612  }
1613  free(stringbuffer_finish(sbuf));
1615 
1616  return desc;
1617 }
1618 
1630 static StringBuffer *artifact_msg(unsigned int level, size_t booksize) {
1631  const artifactlist *al;
1632  const artifact *art;
1633  int i, type, index;
1634  int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
1635  StringBuffer *desc, *message = stringbuffer_new();
1636 
1637  /* values greater than 5 create msg buffers that are too big! */
1638  if (book_entries > 5)
1639  book_entries = 5;
1640 
1641  /* lets determine what kind of artifact type randomly.
1642  * Right now legal artifacts only come from those listed
1643  * in art_name_array. Also, we check to be sure an artifactlist
1644  * for that type exists!
1645  */
1646  i = 0;
1647  do {
1648  index = RANDOM()%arraysize(art_name_array);
1649  type = art_name_array[index].type;
1650  al = find_artifactlist(type);
1651  i++;
1652  } while (al == NULL && i < 10);
1653 
1654  if (i == 10) { /* Unable to find a message */
1655  stringbuffer_append_string(message, "None");
1656  return message;
1657  }
1658 
1659  /* There is no reason to start on the artifact list at the beginning. Lets
1660  * take our starting position randomly... */
1661  art = al->items;
1662  for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
1663  if (art == NULL)
1664  art = al->items; /* hmm, out of stuff, loop back around */
1665  art = art->next;
1666  }
1667 
1668  /* Ok, lets print out the contents */
1669  stringbuffer_append_printf(message, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1670 
1671  i = 0;
1672  /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1673  * as long as we have space up to the allowed max # (book_entires)
1674  */
1675  while (book_entries > 0) {
1676  int with_message;
1677  if (art == NULL)
1678  art = al->items;
1679  with_message = (art->item->msg && RANDOM()%4+1 < level) ? 1 : 0;
1680 
1681  desc = artifact_describe(art, al, with_message, index, i++);
1682 
1683  if (stringbuffer_length(message) + stringbuffer_length(desc) >= booksize) {
1684  stringbuffer_delete(desc);
1685  break;
1686  }
1687 
1688  stringbuffer_append_stringbuffer(message, desc);
1689  stringbuffer_delete(desc);
1690 
1691  art = art->next;
1692  book_entries--;
1693  }
1694 
1695  return message;
1696 }
1697 
1698 /*****************************************************************************
1699  * Spellpath message generation
1700  *****************************************************************************/
1701 
1715 static StringBuffer *spellpath_msg(int level, size_t booksize, StringBuffer *buf) {
1716  int path = RANDOM()%NRSPELLPATHS, prayers = RANDOM()%2;
1717  int did_first_sp = 0;
1718  uint32_t pnum = spellpathdef[path];
1719  archetype *at;
1720 
1721  if (buf == NULL) {
1722  buf = stringbuffer_new();
1723  /* Preamble */
1724  stringbuffer_append_printf(buf, "Herein are detailed the names of %s", prayers ? "prayers" : "incantations");
1725  stringbuffer_append_printf(buf, " belonging to the path of %s:\n ", spellpathnames[path]);
1726  }
1727 
1728  for (at = first_archetype; at != NULL; at = at->next) {
1729  /* Determine if this is an appropriate spell. Must
1730  * be of matching path, must be of appropriate type (prayer
1731  * or not), and must be within the valid level range.
1732  */
1733  if (at->clone.type == SPELL
1734  && at->clone.path_attuned&pnum
1735  && ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers))
1736  && at->clone.level < level*8) {
1737  if (strlen(at->clone.name) + stringbuffer_length(buf) >= booksize)
1738  break;
1739 
1740  if (did_first_sp)
1741  stringbuffer_append_string(buf, ",\n ");
1742  did_first_sp = 1;
1744  }
1745  }
1746 
1747  /* Geez, no spells were generated. */
1748  if (!did_first_sp) {
1749  if (RANDOM()%4) { /* usually, lets make a recursive call... */
1750  return spellpath_msg(level, booksize, buf);
1751  }
1752  /* give up, cause knowing no spells exist for path is info too. need the header too. */
1753  stringbuffer_append_string(buf, "- no known spells exist -\n");
1754  }
1755  return buf;
1756 }
1757 
1766 static void make_formula_book(object *book, int level) {
1767  recipelist *fl;
1768  recipe *formula;
1769  int chance, count = 0;
1770  const char *op_name;
1771  archetype *at;
1772  StringBuffer *text, *title;
1773  char *final, km[MAX_BUF];
1774 
1775  /* the higher the book level, the more complex (ie number of
1776  * ingredients) the formula can be.
1777  */
1778  fl = get_formulalist((RANDOM()%level)/3+1);
1779  if (!fl)
1780  fl = get_formulalist(1); /* safety */
1781 
1782  if (fl->total_chance == 0) {
1783  object_set_msg(book, " <indecipherable text>\n");
1785  add_author(book, MSGTYPE_ALCHEMY);
1786  return;
1787  }
1788 
1789  /* get a random formula, weighted by its bookchance */
1790  chance = RANDOM()%fl->total_chance;
1791  for (formula = fl->items; formula != NULL; formula = formula->next) {
1792  chance -= formula->chance;
1793  if (chance <= 0 && formula->chance != 0 && !formula->is_combination)
1794  break;
1795  }
1796 
1797  if (!formula || formula->arch_names <= 0) {
1798  object_set_msg(book, " <indecipherable text>\n");
1800  add_author(book, MSGTYPE_ALCHEMY);
1801  return;
1802  }
1803 
1804  /* looks like a formula was found. Base the amount
1805  * of information on the booklevel and the spellevel
1806  * of the formula. */
1807 
1808  op_name = formula->arch_name[RANDOM()%formula->arch_names];
1809  at = find_archetype(op_name);
1810  if (at == (archetype *)NULL) {
1811  LOG(llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1812  object_set_msg(book, " <indecipherable text>\n");
1814  add_author(book, MSGTYPE_ALCHEMY);
1815  return;
1816  }
1817  op_name = at->clone.name;
1818 
1819  text = stringbuffer_new();
1820  title = stringbuffer_new();
1821 
1822  /* preamble */
1823  stringbuffer_append_printf(text, "Herein is described a project using %s:\n", formula->skill ? formula->skill : "an unknown skill");
1824 
1825  /* item name */
1826  if (strcmp(formula->title, "NONE")) {
1827  stringbuffer_append_printf(text, "The %s of %s", op_name, formula->title);
1828  /* This results in things like pile of philo. sulfur.
1829  * while philo. sulfur may look better, without this,
1830  * you get things like 'the wise' because its missing the
1831  * water of section.
1832  */
1833  stringbuffer_append_printf(title, "%s: %s of %s", formula_book_name[RANDOM()%arraysize(formula_book_name)], op_name, formula->title);
1834  } else {
1835  stringbuffer_append_printf(text, "The %s", op_name);
1837  if (at->clone.title) {
1838  stringbuffer_append_printf(text, " %s", at->clone.title);
1839  stringbuffer_append_printf(title, " %s", at->clone.title);
1840  }
1841  }
1842  /* Lets name the book something meaningful ! */
1843  if (book->name)
1844  free_string(book->name);
1845  book->name = stringbuffer_finish_shared(title);
1846  if (book->title) {
1847  free_string(book->title);
1848  book->title = NULL;
1849  }
1850 
1851  /* ingredients to make it */
1852  if (formula->ingred != NULL) {
1853  linked_char *next;
1854  archetype *at;
1855  char name[MAX_BUF];
1856 
1857  at = find_archetype(formula->cauldron);
1858  if (at)
1859  query_name(&at->clone, name, MAX_BUF);
1860  else
1861  snprintf(name, sizeof(name), "an unknown place");
1862 
1863  stringbuffer_append_printf(text, " may be made at %s using the following ingredients:\n", name);
1864 
1865  for (next = formula->ingred; next != NULL; next = next->next) {
1866  count++;
1867  stringbuffer_append_printf(text, "%s\n", next->name);
1868  }
1869  } else {
1870  LOG(llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, formula->title);
1871  stringbuffer_append_string(text, "\n");
1872  }
1873 
1874  final = stringbuffer_finish(text);
1875  object_set_msg(book, final);
1876  free(final);
1877 
1880  snprintf(km, sizeof(km), "alchemy:%d:%d:%s", count, formula->index, formula->title);
1881  object_set_value(book, "knowledge_marker", km, 1);
1882 }
1883 
1894 static StringBuffer *msgfile_msg(object *book, size_t booksize) {
1895  int weight;
1896  GeneralMessage *msg = NULL;
1897  StringBuffer *ret = stringbuffer_new();
1898 
1899  /* get a random message for the 'book' from linked list */
1900  if (msg_total_chance > 0) {
1901  assert(first_msg != NULL);
1902  msg = first_msg;
1903  weight = (RANDOM() % msg_total_chance);
1904  while (msg) {
1905  weight -= msg->chance;
1906  if (weight < 0)
1907  break;
1908  msg = msg->next;
1909  }
1910  /* if msg is NULL, then something is really wrong in the computation! */
1911  assert(msg != NULL);
1912  }
1913 
1914  if (msg && strlen(msg->message) <= booksize) {
1916  if (msg->identifier != NULL) {
1917  char km[HUGE_BUF];
1920  snprintf(km, sizeof(km), "message:%s", msg->identifier);
1921  object_set_value(book, "knowledge_marker", km, 1);
1922  }
1923  if (msg->quest_code) {
1924  /* add a 'apply' hook to launch the quest */
1925  object *event = object_create_arch(find_archetype("quest_advance_apply"));
1926  FREE_AND_COPY(event->name, msg->quest_code);
1927  object_insert_in_ob(event, book);
1928  }
1929  } else
1930  stringbuffer_append_string(ret, "\n <undecipherable text>");
1931 
1932  return ret;
1933 }
1934 
1949 static StringBuffer *god_info_msg(int level, size_t booksize, object *book) {
1950  int what = 0;
1951  const object *god = pntr_to_god_obj(get_rand_god());
1952  StringBuffer *desc = NULL;
1953 
1954  if (!god)
1955  return NULL; /* oops, problems... */
1956 
1957  if (booksize > BOOK_BUF) {
1958  LOG(llevError, "common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (unsigned long)booksize, BOOK_BUF);
1959  booksize = BOOK_BUF;
1960  }
1961 
1962  if (level >= 2 && RANDOM()%2) {
1963  what |= GOD_ENEMY;
1964  }
1965  if (level >= 3 && RANDOM()%2) {
1966  what |= GOD_HOLYWORD;
1967  }
1968  if (level >= 4 && RANDOM()%2) {
1969  what |= GOD_RESISTANCES;
1970  }
1971  if (level >= 5 && RANDOM()%2) {
1972  what |= GOD_SACRED;
1973  }
1974  if (level >= 6 && RANDOM()%2) {
1975  what |= GOD_BLESSED;
1976  }
1977  if (level >= 8 && RANDOM()%2) {
1978  what |= GOD_IMMUNITIES;
1979  }
1980  if (level >= 12 && RANDOM()%2) {
1981  what |= GOD_PATHS;
1982  }
1983 
1984  desc = stringbuffer_new();
1985  what = describe_god(god, what, desc, booksize);
1986 
1987  /* check to be sure new buffer size dont exceed either
1988  * the maximum buffer size, or the 'natural' size of the
1989  * book... */
1990  if (stringbuffer_length(desc) > 1 && stringbuffer_length(desc) <= booksize) {
1991  char buf[BOOK_BUF];
1992  snprintf(buf, sizeof(buf), "god:%s:%d", god->name, what);
1993  object_set_value(book, "knowledge_marker", buf, 1);
1994  return desc;
1995  }
1996 
1997  stringbuffer_delete(desc);
1998  return NULL;
1999 }
2000 
2019 void tailor_readable_ob(object *book, int msg_type) {
2020  int level = book->level ? RANDOM()%book->level+1 : 1;
2021  size_t book_buf_size;
2022  StringBuffer *message = NULL;
2023 
2024  /* safety */
2025  if (book->type != BOOK)
2026  return;
2027 
2028  if (level <= 0)
2029  return; /* if no level no point in doing any more... */
2030 
2031  /* Max text length this book can have. */
2032  book_buf_size = BOOKSIZE(book);
2033  book_buf_size -= strlen("\n"); /* Keep enough for final \n. */
2034  assert(book_buf_size < BOOK_BUF);
2035 
2036  /* &&& The message switch &&& */
2037  /* Below all of the possible types of messages in the "book"s.
2038  */
2039  /*
2040  * IF you add a new type of book msg, you will have to do several things.
2041  * 1) make sure there is an entry in the msg switch below!
2042  * 2) make sure there is an entry in max_titles[] array.
2043  * 3) make sure there are entries for your case in new_text_title()
2044  * and add_authour().
2045  * 4) you may want separate authour/book name arrays in read.h
2046  */
2047 
2048  if (msg_type >= (int)arraysize(max_titles))
2049  msg_type = 0;
2050 
2051  msg_type = msg_type > 0 ? msg_type : RANDOM()%6;
2052  switch (msg_type) {
2053  case MSGTYPE_MONSTER:
2054  message = mon_info_msg(level, book_buf_size, book);
2055  break;
2056 
2057  case MSGTYPE_ARTIFACT:
2058  message = artifact_msg(level, book_buf_size);
2059  break;
2060 
2061  case MSGTYPE_SPELLPATH: /* grouping incantations/prayers by path */
2062  message = spellpath_msg(level, book_buf_size, NULL);
2063  break;
2064 
2065  case MSGTYPE_ALCHEMY: /* describe an alchemy formula */
2066  make_formula_book(book, level);
2067  /* make_formula_book already gives title */
2068  return;
2069  break;
2070 
2071  case MSGTYPE_GODS: /* bits of information about a god */
2072  message = god_info_msg(level, book_buf_size, book);
2073  break;
2074 
2075  case MSGTYPE_LIB: /* use info list in lib/ */
2076  default:
2077  message = msgfile_msg(book, book_buf_size);
2078  break;
2079  }
2080 
2081  if (message != NULL) {
2082  char *final;
2083  stringbuffer_append_string(message, "\n");
2084  final = stringbuffer_finish(message);
2085  object_set_msg(book, final);
2086  free(final);
2087  /* lets give the "book" a new name, which may be a compound word */
2088  change_book(book, msg_type);
2089  }
2090 }
2091 
2092 /*****************************************************************************
2093  *
2094  * Cleanup routine for readable stuff.
2095  *
2096  *****************************************************************************/
2097 
2101 void free_all_readable(void) {
2102  titlelist *tlist, *tnext;
2103  title *title1, *titlenext;
2104  GeneralMessage *lmsg, *nextmsg;
2105  objectlink *monlink, *nextmon;
2106 
2107  LOG(llevDebug, "freeing all book information\n");
2108 
2109  for (tlist = booklist; tlist != NULL; tlist = tnext) {
2110  tnext = tlist->next;
2111  for (title1 = tlist->first_book; title1; title1 = titlenext) {
2112  titlenext = title1->next;
2113  if (title1->name)
2114  free_string(title1->name);
2115  if (title1->authour)
2116  free_string(title1->authour);
2117  if (title1->archname)
2118  free_string(title1->archname);
2119  free(title1);
2120  }
2121  free(tlist);
2122  }
2123  for (lmsg = first_msg; lmsg; lmsg = nextmsg) {
2124  nextmsg = lmsg->next;
2125  if (lmsg->identifier)
2126  free_string(lmsg->identifier);
2127  if (lmsg->title)
2128  free_string(lmsg->title);
2129  if (lmsg->message)
2130  free_string(lmsg->message);
2131  if (lmsg->quest_code)
2132  free_string(lmsg->quest_code);
2133  free(lmsg);
2134  }
2135  for (monlink = first_mon_info; monlink; monlink = nextmon) {
2136  nextmon = monlink->next;
2137  free(monlink);
2138  }
2139 }
2140 
2141 /*****************************************************************************
2142  *
2143  * Writeback routine for updating the bookarchive.
2144  *
2145  ****************************************************************************/
2146 
2151  FILE *fp;
2152  OutputFile of;
2153  int index;
2154  char fname[MAX_BUF];
2155  title *book;
2156  titlelist *bl;
2157 
2158  /* If nothing changed, don't write anything */
2160  return;
2161 
2162  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
2163  LOG(llevDebug, "Updating book archive: %s...\n", fname);
2164 
2165  fp = of_open(&of, fname);
2166  if (fp == NULL)
2167  return;
2168 
2169  for (bl = get_titlelist(0), index = 0; bl; bl = bl->next, index++) {
2170  for (book = bl->first_book; book; book = book->next)
2171  if (book && book->authour) {
2172  fprintf(fp, "title %s\n", book->name);
2173  fprintf(fp, "authour %s\n", book->authour);
2174  fprintf(fp, "arch %s\n", book->archname);
2175  fprintf(fp, "level %d\n", book->level);
2176  fprintf(fp, "type %d\n", index);
2177  /* C89 doesn't have %zu... */
2178  fprintf(fp, "size %lu\n", (unsigned long)book->size);
2179  fprintf(fp, "index %d\n", book->msg_index);
2180  fprintf(fp, "end\n");
2181  }
2182  }
2183  if (!of_close(&of))
2184  return;
2185 
2186  if (chmod(fname, SAVE_MODE) != 0) {
2187  LOG(llevError, "Could not set permissions on '%s'\n", fname);
2188  }
2189 
2191 }
2192 
2201  uint8_t subtype = readable->subtype;
2202 
2203  if (subtype > last_readable_subtype)
2204  return &readable_message_types[0];
2205  return &readable_message_types[subtype];
2206 }
2207 
2213 const GeneralMessage *get_message_from_identifier(const char *identifier) {
2214  GeneralMessage *msg = first_msg;
2215  while (msg && ((msg->identifier == 0) || (strcmp(msg->identifier, identifier) != 0)))
2216  msg = msg->next;
2217 
2218  return msg;
2219 }
2220 
2227  return message->title;
2228 }
2229 
2236  return message->message;
2237 }
2238 
2244 unsigned int get_message_face(const GeneralMessage *message) {
2245  return message->face;
2246 }
Error, serious thing.
Definition: logger.h:11
#define MSG_TYPE_PAPER_SCROLL_OLD_1
Definition: newclient.h:437
#define MSG_TYPE_SIGN_DIR_LEFT
Definition: newclient.h:445
static const char *const heavy_book_name[]
Name for big books.
Definition: readable.c:397
archetype * find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:695
uint8_t type
Object type that this list represents.
Definition: artifact.h:27
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
#define GOD_BLESSED
Write various information (resistances?).
Definition: god.h:28
Spell-related defines: spellpath, subtypes, ...
Information.
Definition: logger.h:12
See Ring.
Definition: object.h:185
static const uint32_t spellpathdef[NRSPELLPATHS]
Spellpath information.
Definition: readable.c:174
#define MSG_TYPE_PAPER_LETTER_NEW_1
Definition: newclient.h:433
#define PATH_MISSILE
Definition: spells.h:17
#define MSGTYPE_ARTIFACT
Artifact-related information.
Definition: readable.c:81
Used to link together several objects.
Definition: object.h:442
#define MSG_TYPE_CARD_ELEGANT_1
Definition: newclient.h:417
static void init_msgfile(void)
If not called before, initialize the info list.
Definition: readable.c:728
#define PATH_MIND
Definition: spells.h:23
#define SET_FLAG(xyz, p)
Definition: define.h:223
See Bracers.
Definition: object.h:217
sstring get_message_title(const GeneralMessage *message)
Get a message&#39;s title.
Definition: readable.c:2226
static void make_formula_book(object *book, int level)
Generate a message detailing the properties of a randomly selected alchemical formula.
Definition: readable.c:1766
const artifactlist * find_artifactlist(int type)
Searches the artifact lists and returns one that has the same type of objects on it.
Definition: artifact.c:630
static titlelist * get_titlelist(int i)
Gets the ith titlelist.
Definition: readable.c:619
static void add_book_to_list(const object *book, int msgtype)
Adds a book to the list of existing books.
Definition: readable.c:1197
unsigned char uint8_t
Definition: win32.h:161
#define PATH_TURNING
Definition: spells.h:29
void stringbuffer_append_stringbuffer(StringBuffer *sb, const StringBuffer *sb2)
Append the contents of a string buffer instance to another string buffer instance.
Definition: stringbuffer.c:131
const char * archname
the archetype name of the book
Definition: readable.c:109
#define MSG_TYPE_CARD_MONEY_1
Definition: newclient.h:423
object * get_random_mon(int level)
Returns a random monster selected from linked list of all monsters in the current game...
Definition: readable.c:1371
#define MSG_TYPE_CARD_MONEY_3
Definition: newclient.h:425
See Cloak.
Definition: object.h:204
See Food.
Definition: object.h:112
#define PATH_LIGHT
Definition: spells.h:32
Information on one title.
Definition: readable.c:106
See Projectile.
Definition: object.h:117
sstring title
The message&#39;s title, only used for knowledge.
Definition: readable.c:138
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.c:85
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.c:596
struct artifactstruct * items
Artifacts for this type.
Definition: artifact.h:30
object * mon
Definition: comet_perf.c:74
static const arttypename art_name_array[]
Artiface/item information.
Definition: readable.c:230
#define MSG_TYPE_CARD_SIMPLE_2
Definition: newclient.h:415
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.c:57
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define MSG_TYPE_MONUMENT_STATUE_3
Definition: newclient.h:456
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
unsigned int get_message_face(const GeneralMessage *message)
Get a message&#39;s face.
Definition: readable.c:2244
#define MSGTYPE_MONSTER
Monster-related information.
Definition: readable.c:79
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.c:4246
#define MSG_TYPE_MONUMENT_WALL_2
Definition: newclient.h:461
#define MSG_TYPE_PAPER_NOTE_2
Definition: newclient.h:429
object clone
An object from which to do object_copy()
Definition: object.h:470
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
static const int last_readable_subtype
Number of elements in readable_message_types.
Definition: readable.c:547
#define MSG_TYPE_SIGN_DIR_RIGHT
Definition: newclient.h:446
static const char *const path_book_name[]
Book names for path information.
Definition: readable.c:198
See Weapon.
Definition: object.h:119
static void init_book_archive(void)
If not called before, initialize the info list.
Definition: readable.c:837
#define MSG_TYPE_PAPER_ENVELOPE_1
Definition: newclient.h:435
See Helmet.
Definition: object.h:136
#define MSG_TYPE_BOOK_SPELL_SORCERER
Definition: newclient.h:410
#define MSG_TYPE_PAPER_SCROLL_NEW_1
Definition: newclient.h:439
static int msg_total_chance
Total chance of messages (GeneralMessage), to randomly select one.
Definition: readable.c:169
#define PATH_RESTORE
Definition: spells.h:21
#define GOD_HOLYWORD
Write holy word information.
Definition: god.h:25
int msg_index
an index value derived from book message
Definition: readable.c:112
uint8_t subtype
Subtype of object.
Definition: object.h:339
See Rod.
Definition: object.h:109
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
Definition: newclient.h:457
#define PATH_FIRE
Definition: spells.h:14
#define MSG_TYPE_BOOK_QUARTO_2
Definition: newclient.h:406
const char * name
the name of the book
Definition: readable.c:107
#define MSG_TYPE_MONUMENT_STONE_1
Definition: newclient.h:451
See Girdle.
Definition: object.h:223
#define MSG_TYPE_MONUMENT_STONE_3
Definition: newclient.h:453
int is_combination
Whather this is an alchemy recipe, or an item transformation description.
Definition: recipe.h:31
static title * find_title(const object *book, int msgtype)
Search the titlelist (based on msgtype) to see if book matches something already there.
Definition: readable.c:1037
See Amulet.
Definition: object.h:139
#define MSG_TYPE_BOOK_SPELL_PRAYER
Definition: newclient.h:408
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:343
#define MSGTYPE_ALCHEMY
Alchemy-related information.
Definition: readable.c:85
int16_t sp
Spell points.
Definition: living.h:41
static object * get_next_mon(const object *tmp)
This function returns the next monster after &#39;tmp&#39; in the monster list.
Definition: readable.c:1452
sstring identifier
Message identifier, can be NULL.
Definition: readable.c:137
#define MSG_TYPE_BOOK_SPELL_PYRO
Definition: newclient.h:409
Global type definitions and header inclusions.
See Boots.
Definition: object.h:212
#define MSG_TYPE_BOOK_ELEGANT_1
Definition: newclient.h:403
tag_t id
ob&#39;s tag, in case it is removed.
Definition: object.h:445
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:465
#define MSG_TYPE_PAPER_NOTE_3
Definition: newclient.h:430
const char *const spellpathnames[NRSPELLPATHS]
Perhaps not the best place for this, but needs to be in some file in the common area so that standalo...
Definition: init.c:120
#define MSG_TYPE_CARD_STRANGE_1
Definition: newclient.h:420
struct titlestruct title
Information on one title.
object * ob
Item to link to.
Definition: object.h:443
unsigned int face
Face the message displays at in the knowledge dialog, -1 if no face defined.
Definition: readable.c:141
#define GOD_RESISTANCES
Write resistances.
Definition: god.h:26
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.c:4375
int chance
Chance that recipe for this item will appear in an alchemical grimore.
Definition: recipe.h:14
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
const char * title
Of foo, etc.
Definition: object.h:317
#define PATH_ELEC
Definition: spells.h:16
#define MSG_TYPE_CARD_ELEGANT_3
Definition: newclient.h:419
static const char *const mon_book_name[]
Monster book information.
Definition: readable.c:278
int nstrtok(const char *buf1, const char *buf2)
Simple routine to return the number of list items in buf1 as separated by the value of buf2...
Definition: readable.c:650
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
We don&#39;t want to exceed the buffer size of buf1 by adding on buf2!
Definition: shstr.c:398
#define MSG_TYPE_PAPER_SCROLL_OLD_2
Definition: newclient.h:438
struct titlestruct * next
next item in the list
Definition: readable.c:113
See Shooting Weapon.
Definition: object.h:118
const char * name
generic name to call artifacts of this type
Definition: readable.c:127
struct titleliststruct titlelist
Titles for one message type.
uint16_t total_chance
Sum of chance for are artifacts on this list.
Definition: artifact.h:28
See Book.
Definition: object.h:114
#define MSG_TYPE_CARD_SIMPLE_3
Definition: newclient.h:416
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it...
Definition: object.c:1037
sstring title
Distinguishing name of product.
Definition: recipe.h:11
const char * name_pl
The plural name of the object.
Definition: object.h:315
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.c:620
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.c:95
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
int total_chance
Total chance of the recipes in this list.
Definition: recipe.h:38
static StringBuffer * artifact_msg(unsigned int level, size_t booksize)
Generate a message detailing the properties of 1-6 artifacts drawn sequentially from the artifact lis...
Definition: readable.c:1630
int32_t weight
Attributes of the object.
Definition: object.h:365
#define MSG_TYPE_BOOK_ELEGANT_2
Definition: newclient.h:404
#define FLAG_UNAGGRESSIVE
Monster doesn&#39;t attack players.
Definition: define.h:272
static StringBuffer * mon_info_msg(int level, size_t booksize, object *book)
Generate a message detailing the properties of randomly monster(s), and add relevant knowledge marker...
Definition: readable.c:1480
struct namebytype arttypename
special structure, used only by art_name_array[]
#define MSG_TYPE_PAPER_SCROLL_MAGIC
Definition: newclient.h:441
#define BOOK_BUF
Maximum message buf size for books.
Definition: book.h:16
#define snprintf
Definition: win32.h:46
#define MSG_TYPE_MONUMENT_WALL_3
Definition: newclient.h:462
#define GOD_IMMUNITIES
Write immunities.
Definition: god.h:29
static StringBuffer * artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator)
Describe an artifact.
Definition: readable.c:1535
struct linked_char * next
Definition: global.h:88
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
#define PATH_TRANSMUTE
Definition: spells.h:27
#define MSG_TYPE_CARD_SIMPLE_1
Definition: newclient.h:414
GeneralMessage * next
Next message in the list.
Definition: readable.c:142
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
Definition: recipe.c:640
godlink * get_rand_god(void)
Returns a random god.
Definition: holy.c:101
int of_close(OutputFile *of)
Closes an output file.
Definition: output_file.c:61
static int need_to_write_bookarchive
If set then we have information to save.
Definition: readable.c:157
#define PATH_DEATH
Definition: spells.h:31
const char * name
The name of the object, obviously...
Definition: object.h:311
#define FLAG_CHANGING
Changes to other_arch when anim is done.
Definition: define.h:263
linked_char * allowed
List of archetypes the artifact can affect.
Definition: artifact.h:19
struct titleliststruct * next
pointer to next book list
Definition: readable.c:122
unsigned int level
level of difficulty of this message
Definition: readable.c:110
special structure, used only by art_name_array[]
Definition: readable.c:126
#define MSG_TYPE_CARD_STRANGE_3
Definition: newclient.h:422
archetype * find_archetype_by_object_name(const char *name)
This function retrieves an archetype given the name that appears during the game (for example...
Definition: arch.c:57
size_t stringbuffer_length(StringBuffer *sb)
Return the current length of the buffer.
Definition: stringbuffer.c:154
int chance
Relative chance of the message appearing randomly.
Definition: readable.c:135
void tailor_readable_ob(object *book, int msg_type)
The main routine.
Definition: readable.c:2019
Struct to store the message_type and message_subtype for signs and books used by the player...
Definition: book.h:36
#define PATH_PROT
Definition: spells.h:13
const object * pntr_to_god_obj(godlink *godlnk)
Returns a pointer to the object We need to be VERY careful about using this, as we are returning a po...
Definition: holy.c:123
static const char *const book_author[]
Used by &#39;generic&#39; books.
Definition: readable.c:410
#define arraysize(arrayname)
Returns the element size of an array.
Definition: readable.c:96
This represents all archetypes for one particular object type.
Definition: artifact.h:26
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Describe a god.
Definition: holy.c:137
static const char *const gods_author[]
Used by gods texts.
Definition: readable.c:328
archetype * try_find_archetype(const char *name)
Finds, using the hashtable, which archetype matches the given name.
Definition: arch.c:666
#define PATH_SELF
Definition: spells.h:18
static int nrofmon
Number of monsters in the first_mon_info list.
Definition: readable.c:156
static titlelist * booklist
Buffer of books read in from the bookarch file.
Definition: readable.c:151
sstring skill
Skill name used to make this recipe.
Definition: recipe.h:26
static void add_book(title *book, int type, const char *fname, int lineno)
Appends a book to the booklist.
Definition: readable.c:955
See Spell.
Definition: object.h:214
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
Titles for one message type.
Definition: readable.c:119
void init_readable(void)
Initialize linked lists utilized by message functions in tailor_readable_ob()
Definition: readable.c:1005
#define MSG_TYPE_BOOK_SPELL_SUMMONER
Definition: newclient.h:411
#define MSG_TYPE_SIGN_BASIC
Definition: newclient.h:444
static void add_author(object *op, int msgtype)
A lot like new_text_name() above, but instead chooses an author and sets op->title to that value...
Definition: readable.c:1125
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
sstring quest_code
Optional quest code and state this message will start.
Definition: readable.c:140
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40
This is one artifact, ie one special item.
Definition: artifact.h:14
static StringBuffer * god_info_msg(int level, size_t booksize, object *book)
Generate a message detailing the properties of a random god.
Definition: readable.c:1949
object * object_create_arch(archetype *at)
Create a full object using the given archetype.
Definition: arch.c:736
static GeneralMessage * first_msg
First message from data read from the messages file.
Definition: readable.c:164
#define MSG_TYPE_CARD
Definition: newclient.h:371
#define MSGTYPE_SPELLPATH
Spellpath-related information.
Definition: readable.c:83
static const char *const mon_author[]
Used by monster beastuary texts.
Definition: readable.c:295
#define MSG_TYPE_CARD_STRANGE_2
Definition: newclient.h:421
#define MSG_TYPE_MONUMENT_STATUE_2
Definition: newclient.h:455
static StringBuffer * msgfile_msg(object *book, size_t booksize)
Generate a message drawn randomly from lib/messages.
Definition: readable.c:1894
#define PATH_CREATE
Definition: spells.h:24
#define BOOKSIZE(xyz)
Get the book buffer size for an individual book object.
Definition: book.h:31
#define MSG_TYPE_PAPER_LETTER_NEW_2
Definition: newclient.h:434
static int unique_book(const object *book, int msgtype)
Check to see if the book title/msg is unique.
Definition: readable.c:1173
static const char *const gods_book_name[]
God book information.
Definition: readable.c:314
const char * sstring
Strings that should be manipulated through add_string() and free_string().
Definition: global.h:40
#define MSG_TYPE_MONUMENT_STONE_2
Definition: newclient.h:452
#define MSG_TYPE_MONUMENT_WALL_1
Definition: newclient.h:460
unsigned int uint32_t
Definition: win32.h:162
const char * datadir
Read only data files.
Definition: global.h:244
#define MSG_TYPE_BOOK_CLASP_1
Definition: newclient.h:401
See Shield.
Definition: object.h:135
const char * authour
the name of the book authour
Definition: readable.c:108
#define MSG_TYPE_MONUMENT
Definition: newclient.h:374
const char * name
Definition: global.h:87
#define MSG_TYPE_MONUMENT_STATUE_1
Definition: newclient.h:454
#define PATH_INFO
Definition: spells.h:26
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Describes an item, in all its details.
Definition: item.c:980
#define PATH_FROST
Definition: spells.h:15
static const char *const art_author[]
Used by artifact texts.
Definition: readable.c:265
static titlelist * get_empty_booklist(void)
Creates a titlelist.
Definition: readable.c:574
#define RANDOM()
Definition: define.h:679
static const readable_message_type readable_message_types[]
Each line of this array is a readable subtype.
Definition: readable.c:483
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:213
int16_t grace
Grace.
Definition: living.h:43
#define MSG_TYPE_PAPER_SCROLL_NEW_2
Definition: newclient.h:440
Also see SKILL_TOOL (74) below.
Definition: object.h:143
#define GOD_ENEMY
Write down god&#39;s enemy.
Definition: god.h:24
#define MSG_TYPE_CARD_ELEGANT_2
Definition: newclient.h:418
#define PATH_TRANSFER
Definition: spells.h:28
const char * localdir
Read/write data files.
Definition: global.h:245
living stats
Str, Con, Dex, etc.
Definition: object.h:368
#define MSG_TYPE_CARD_MONEY_2
Definition: newclient.h:424
static const char *const formula_author[]
This isn&#39;t used except for empty books.
Definition: readable.c:358
struct archt * arch
Pointer to archetype.
Definition: object.h:412
int type
matching type
Definition: readable.c:128
int allowed_size
Length of allowed, for faster computation.
Definition: artifact.h:20
struct oblnk * next
Next item to link to.
Definition: object.h:444
size_t arch_names
Size of the arch_name[] array.
Definition: recipe.h:12
#define MSG_TYPE_SIGN_MAGIC_MOUTH
Definition: newclient.h:448
Only for debugging purposes.
Definition: logger.h:13
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
Definition: stringbuffer.c:71
int number
number of items in the list
Definition: readable.c:120
#define MSG_TYPE_PAPER_ENVELOPE_2
Definition: newclient.h:436
#define GOD_PATHS
Path information.
Definition: god.h:30
#define PATH_ABJURE
Definition: spells.h:20
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
struct Settings settings
Server settings.
Definition: init.c:40
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.c:30
#define MSG_TYPE_PAPER
Definition: newclient.h:372
#define GOD_SACRED
Write sacred creatures.
Definition: god.h:27
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
Checks if buf1 and buf2 can be combined.
Definition: readable.c:710
struct archt * next
Next archetype in a linked list.
Definition: object.h:467
#define MSGTYPE_MSGFILE
Message from the lib/messages file.
Definition: readable.c:89
#define SAVE_MODE
If you have defined SAVE_PLAYER, you might want to change this, too.
Definition: config.h:616
const GeneralMessage * get_message_from_identifier(const char *identifier)
Find the message from its identifier.
Definition: readable.c:2213
#define MSG_TYPE_PAPER_LETTER_OLD_2
Definition: newclient.h:432
void free_all_readable(void)
Free all readable-related information.
Definition: readable.c:2101
Functions for creating text output files.
struct recipestruct * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
static const int max_titles[6]
Number of titles for different name lists.
Definition: readable.c:550
static const char *const path_author[]
Used by spellpath texts.
Definition: readable.c:207
void add_abilities(object *op, const object *change)
Used in artifact generation.
Definition: artifact.c:284
const char * msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
void write_book_archive(void)
Write out the updated book archive to bookarch file.
Definition: readable.c:2150
sstring get_message_body(const GeneralMessage *message)
Get a message&#39;s body.
Definition: readable.c:2235
static const char *const light_book_name[]
Generic book information.
Definition: readable.c:380
static StringBuffer * mon_desc(const object *mon)
Returns a description of the monster.
Definition: readable.c:1434
#define MSG_TYPE_PAPER_LETTER_OLD_1
Definition: newclient.h:431
char * strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size)
Takes a string in buf1 and separates it into a list of strings delimited by buf2. ...
Definition: readable.c:680
static objectlink * first_mon_info
Information on monsters.
Definition: readable.c:154
sstring add_string(const char *str)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
struct titlestruct * first_book
pointer to first book in this list
Definition: readable.c:121
#define MSG_TYPE_BOOK_SPELL_EVOKER
Definition: newclient.h:407
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.c:104
#define MSG_TYPE_SIGN_DIR_BOTH
Definition: newclient.h:447
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
Definition: newclient.h:458
static void change_book(object *book, int msgtype)
Give a new, fancier name to generated objects of type BOOK and SPELLBOOK.
Definition: readable.c:1239
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
void object_copy(const object *src_ob, object *dest_ob)
Copy object first frees everything allocated by the second object, and then copies the contents of th...
Definition: object.c:838
static void init_mon_info(void)
Creates the linked list of pointers to monster archetype objects if not called previously.
Definition: readable.c:973
const readable_message_type * get_readable_message_type(object *readable)
Get the readable type for an object (hopefully book).
Definition: readable.c:2200
See Gloves.
Definition: object.h:213
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
Definition: newclient.h:459
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define MSGTYPE_LIB
Message from the lib/messages file.
Definition: readable.c:77
#define MSG_TYPE_BOOK
Definition: newclient.h:370
One general message, from the lib/messages file.
Definition: readable.c:134
Structure containing object statistics.
void object_set_msg(object *op, const char *msg)
Set the message field of an object.
Definition: object.c:4695
static const char *const formula_book_name[]
Alchemy (formula) information.
Definition: readable.c:346
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.c:25
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
object * item
Special values of the artifact.
Definition: artifact.h:15
#define PATH_DETONATE
Definition: spells.h:22
uint16_t chance
Chance of the artifact to happen.
Definition: artifact.h:16
#define MSG_TYPE_BOOK_QUARTO_1
Definition: newclient.h:405
static const char *const book_descrpt[]
Book descriptions.
Definition: readable.c:456
#define MSGTYPE_GODS
God-related information.
Definition: readable.c:87
static void new_text_name(object *book, int msgtype)
Only for objects of type BOOK.
Definition: readable.c:1076
static const char *const art_book_name[]
Book titles for artifact information.
Definition: readable.c:250
size_t size
size of the book message
Definition: readable.c:111
See Breastplate Armor.
Definition: object.h:120
int16_t level
Level of creature or object.
Definition: object.h:351
#define MSG_TYPE_PAPER_NOTE_1
Definition: newclient.h:428
#define MSG_TYPE_BOOK_CLASP_2
Definition: newclient.h:402
static StringBuffer * spellpath_msg(int level, size_t booksize, StringBuffer *buf)
Generate a message detailing the member incantations/prayers (and some of their properties) belonging...
Definition: readable.c:1715
unsigned find_face(const char *name, unsigned error)
This returns an the face number of face &#39;name&#39;.
Definition: image.c:303
Describes fundental parameters of &#39;books&#39; - objects with type==BOOK.
EXTERN archetype * first_archetype
First archetype.
Definition: global.h:122
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.c:76
#define PATH_WOUNDING
Definition: spells.h:30
struct recipestruct * items
Pointer to first recipe in this list.
Definition: recipe.h:40
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.c:114
struct artifactstruct * next
Next artifact in the list.
Definition: artifact.h:18
#define MSG_TYPE_SIGN
Definition: newclient.h:373
One alchemy recipe.
Definition: recipe.h:10
sstring message
The message&#39;s body.
Definition: readable.c:139
#define PATH_TELE
Definition: spells.h:25
#define MAX_TITLE_CHECK
How many times to try to generate a unique name for a book.
Definition: readable.c:74
#define PATH_SUMMON
Definition: spells.h:19
static title * get_empty_book(void)
Creates a title.
Definition: readable.c:594