Crossfire Server, Trunk  1.75.0
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  "Inioda", /* ancient wizard and biologist */
290  "life",
291  "monsters",
292  "nature",
293  "new life",
294  "residents",
295  "the spawn",
296  "the living",
297  "the wilds",
298  "things"
299 };
300 
304 static const char *const gods_book_name[] = {
305  "devotional",
306  "devout notes",
307  "divine text",
308  "divine work",
309  "holy book",
310  "holy record",
311  "hymnal",
312  "illuminated text",
313  "moral text",
314  "pious pamphlet",
315  "sacred guide",
316  "testament",
317  "transcript",
318 };
319 
321 static const char *const gods_author[] = {
322  "cults",
323  "dieties",
324  "joy",
325  "lasting curse",
326  "madness",
327  "religions",
328  "rituals",
329  "the dead",
330  "the gods",
331  "the heirophant",
332  "the poor priest",
333  "the priestess",
334  "pain",
335  "white",
336  "worship"
337 };
338 
342 static const char *const formula_book_name[] = {
343  "cookbook",
344  "formulary",
345  "lab book",
346  "lab notes",
347  "recipe book",
348  "experiment record",
349  "work plan",
350  "design notes",
351  "research notes",
352  "crafting manual"
353 };
354 
356 static const char *const formula_author[] = {
357  "Albertus Magnus",
358  "alchemy",
359  "balms",
360  "creation",
361  "dusts",
362  "magical manufacture",
363  "making",
364  "philosophical items",
365  "potions",
366  "powders",
367  "the cauldron",
368  "the lamp black",
369  "transmutation",
370  "waters"
371 };
372 
378 static const char *const light_book_name[] = {
379  "calendar",
380  "datebook",
381  "diary",
382  "essay",
383  "guidebook",
384  "handbook",
385  "ledger",
386  "notes",
387  "notebook",
388  "octavo",
389  "opuscule",
390  "pamphlet",
391  "practicum",
392  "script",
393  "transcript"
394 };
395 
397 static const char *const heavy_book_name[] = {
398  "catalog",
399  "compendium",
400  "dissertation",
401  "guide",
402  "manual",
403  "opus",
404  "tome",
405  "treatise",
406  "volume",
407  "work"
408 };
409 
411 static const char *const book_author[] = {
412  "Abdulah",
413  "Al'hezred",
414  "Alywn",
415  "Arundel",
416  "Arvind",
417  "Aerlingas",
418  "Bacon",
419  "Baliqendii",
420  "Bosworth",
421  "Beathis",
422  "Bertil",
423  "Cauchy",
424  "Chakrabarti",
425  "der Waalis",
426  "Dirk",
427  "Djwimii",
428  "Eisenstaadt",
429  "Fendris",
430  "Frank",
431  "Habbi",
432  "Harlod",
433  "Ichibod",
434  "Janus",
435  "June",
436  "Laplace",
437  "Magnuson",
438  "Nandii",
439  "Nitfeder",
440  "Norris",
441  "Parael",
442  "Penhew",
443  "Sophia",
444  "Skilly",
445  "Tahir",
446  "Thockmorton",
447  "Thomas",
448  "van Helsing",
449  "van Pelt",
450  "Voormis",
451  "Xavier",
452  "Xeno",
453  "Zardoz",
454  "Zagy"
455 };
456 
458 static const char *const book_descrpt[] = {
459  "ancient",
460  "cryptic",
461  "cryptical",
462  "dusty",
463  "hierarchical",
464  "grizzled",
465  "gold-gilt",
466  "great",
467  "lost",
468  "magnificent",
469  "musty",
470  "mythical",
471  "mystical",
472  "rustic",
473  "stained",
474  "silvered",
475  "transcendental",
476  "weathered"
477 };
478 
486  /*subtype 0 */ { 0, 0 },
487  /* book messages subtypes */
488  /*subtype 1 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1 },
497  /*subtype 10 */ { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER },
499  /* card messages subtypes*/
508  /*subtype 20 */ { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3 },
512  /* Paper messages subtypes */
519  /*subtype 30 */ { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2 },
527  /* road signs messages subtypes */
530  /*subtype 40 */ { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT },
532  /* stones and monument messages */
546 };
547 
550 
552 static const int max_titles[6] = {
554  arraysize(mon_book_name)*arraysize(mon_author), /* MSGTYPE_MONSTER */
555  arraysize(art_book_name)*arraysize(art_author), /* MSGTYPE_ARTIFACT */
556  arraysize(path_book_name)*arraysize(path_author), /* MSGTYPE_SPELLPATH */
557  arraysize(formula_book_name)*arraysize(formula_author), /* MSGTYPE_ALCHEMY */
558  arraysize(gods_book_name)*arraysize(gods_author), /* MSGTYPE_GODS */
559 };
560 
561 /******************************************************************************
562  *
563  * Start of misc. readable functions used by others functions in this file
564  *
565  *****************************************************************************/
566 
577  titlelist *bl = (titlelist *)calloc(1, sizeof(titlelist));
578 
579  if (bl == NULL)
581  return bl;
582 }
583 
593 static title *get_empty_book(void) {
594  title *t = (title *)calloc(1, sizeof(title));
595 
596  if (t == NULL)
598  return t;
599 }
600 
611 static titlelist *get_titlelist(int i) {
612  titlelist *tl;
613  int number;
614 
615  if (i < 0 || i >= (int)arraysize(max_titles)) {
616  LOG(llevInfo, "Warning: invalid book index %d, using 0 instead\n", i);
617  return booklist;
618  }
619 
620  for (tl = booklist, number = i; tl && number; tl = tl->next, number--) {
621  if (!tl->next)
622  tl->next = get_empty_booklist();
623  }
624 
625  return tl;
626 }
627 
628 /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file
629  * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
630 
642 int nstrtok(const char *buf1, const char *buf2) {
643  char *tbuf, buf[MAX_BUF];
644  int number = 0;
645 
646  if (!buf1 || !buf2)
647  return 0;
648 
649  strlcpy(buf, buf1, sizeof(buf));
650  for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
651  number++;
652  }
653  return number;
654 }
655 
661 const char *trim(const char *buf) {
662  while ((*buf) == ' ') {
663  buf++;
664  }
665  return buf;
666 }
667 
684 char *strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size) {
685  int maxi, i = nstrtok(buf1, buf2);
686  char *tbuf, buf[MAX_BUF];
687 
688  maxi = i;
689  strlcpy(buf, buf1, sizeof(buf));
690  snprintf(retbuf, size, " ");
691  for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
692  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "%s", trim(tbuf));
693  i--;
694  if (i == 1 && maxi > 1)
695  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), " and ");
696  else if (i > 0 && maxi > 1)
697  snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ", ");
698  else {
699  // Remove a trailing newline if it is there.
700  int end = strlen(retbuf);
701  if (retbuf[end-1] == '\n')
702  end--;
703  snprintf(retbuf+end, size-end, ".");
704  }
705  }
706  return retbuf;
707 }
708 
719 int book_overflow(const char *buf1, const char *buf2, size_t booksize) {
720  if (buf_overflow(buf1, buf2, BOOK_BUF-2) /* 2 less so always room for trailing \n */
721  || buf_overflow(buf1, buf2, booksize))
722  return 1;
723  return 0;
724 }
725 
726 /*****************************************************************************
727  *
728  * Start of initialization related functions.
729  *
730  ****************************************************************************/
731 
738 static void init_book_archive(void) {
739  FILE *fp;
740 #ifdef BOOK_MSG_DEBUG
741  int nroftitle = 0;
742 #endif
743  char buf[MAX_BUF], fname[MAX_BUF], *cp;
744  static int did_init_barch = 0;
745 
746  if (did_init_barch)
747  return;
748  did_init_barch = 1;
749 
750  if (!booklist)
752 
753  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
754  LOG(llevDebug, " Reading bookarch from %s...\n", fname);
755 
756  fp = fopen(fname, "r");
757  if (fp != NULL) {
758  int type;
759  size_t i;
760  titlelist *bl;
761  int lineno;
762  title *book;
763  int skipping;
764 
765  skipping = 0;
766  book = NULL;
767  type = -1;
768  for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
769  int len;
770  int value;
771 
772  if (*buf == '#')
773  continue;
774  cp = strchr(buf, '\n');
775  if (cp != NULL) {
776  while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
777  cp--;
778  *cp = '\0';
779  }
780  cp = buf;
781  if (strncmp(buf, "title ", 6) == 0) {
782  skipping = 0;
783  cp = buf+6;
784  while (*cp == ' ' || *cp == '\t')
785  cp++;
786  if (*cp == '\0') {
787  LOG(llevInfo, "Warning: missing book title at %s, line %d\n", fname, lineno);
788  book = NULL;
789  } else {
790  book = get_empty_book(); /* init new book entry */
791  book->name = add_string(cp);
792  type = -1;
793 #ifdef BOOK_MSG_DEBUG
794  nroftitle++;
795 #endif
796  }
797  } else if (book == NULL) {
798  if (!skipping) {
799  skipping = 1;
800  LOG(llevInfo, "Warning: expecting 'title' at %s, line %d\n", fname, lineno);
801  }
802  } else if (strncmp(buf, "authour ", 8) == 0) {
803  cp = buf+8;
804  while (*cp == ' ' || *cp == '\t')
805  cp++;
806  if (*cp == '\0') {
807  LOG(llevInfo, "Warning: missing book authour at %s, line %d\n", fname, lineno);
808  } else {
809  book->authour = add_string(cp);
810  }
811  } else if (strncmp(buf, "arch ", 5) == 0) {
812  cp = buf+5;
813  while (*cp == ' ' || *cp == '\t')
814  cp++;
815  if (*cp == '\0') {
816  LOG(llevInfo, "Warning: missing book arch at %s, line %d\n", fname, lineno);
817  } else {
818  book->archname = add_string(cp);
819  }
820  } else if (sscanf(buf, "level %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
821  book->level = value;
822  } else if (sscanf(buf, "type %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
823  type = value;
824  } else if (sscanf(buf, "size %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
825  book->size = value;
826  } else if (sscanf(buf, "index %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
827  book->msg_index = value;
828  } else if (strcmp(buf, "end") == 0) { /* link it */
829  add_book(book, type, fname, lineno);
830  book = NULL;
831  type = -1;
832  } else {
833  LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
834  }
835  }
836  if (book != NULL) {
837  LOG(llevInfo, "Warning: missing 'end' at %s, line %d\n", fname, lineno);
838  add_book(book, type, fname, lineno);
839  }
840  LOG(llevDebug, " book archives(used/avail):\n");
841  for (bl = booklist, i = 0; bl != NULL && i < arraysize(max_titles); bl = bl->next, i++) {
842  LOG(llevDebug, "(%d/%d)\n", bl->number, max_titles[i]);
843  }
844  fclose(fp);
845  }
846 
847 #ifdef BOOK_MSG_DEBUG
848  LOG(llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle);
849 #endif
850  LOG(llevDebug, " done.\n");
851 }
852 
860 static void add_book(title *book, int type, const char *fname, int lineno) {
861  titlelist *bl;
862 
863  if (type == -1) {
864  LOG(llevInfo, "Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
865  type = 0;
866  }
867 
868  bl = get_titlelist(type);
869  book->next = bl->first_book;
870  bl->first_book = book;
871  bl->number++;
872 }
873 
874 static void do_monster(archetype *at) {
875  if (QUERY_FLAG(&at->clone, FLAG_MONSTER) && (!at->head)
878  monsters.push_back(&at->clone);
879  }
880 }
881 
886 static void init_mon_info(void) {
887  static int did_init_mon_info = 0;
888 
889  if (did_init_mon_info)
890  return;
891  did_init_mon_info = 1;
892 
894 
895  LOG(llevDebug, "init_mon_info() got %zu monsters\n", monsters.size());
896 }
897 
904 void init_readable(void) {
905  static int did_this = 0;
906 
907  if (did_this)
908  return;
909  did_this = 1;
910 
911  LOG(llevDebug, "Initializing reading data...\n");
913  init_mon_info();
914  LOG(llevDebug, " done reading data\n");
915 }
916 
917 /*****************************************************************************
918  *
919  * This is the start of the administrative functions when creating
920  * new books (ie, updating title and the like)
921  *
922  *****************************************************************************/
923 
935 static title *find_title(const object *book, int msgtype) {
936  title *t;
937  titlelist *tl;
938  size_t length;
939  int index;
940 
941  if (msgtype < 0)
942  return (title *)NULL;
943 
944  tl = get_titlelist(msgtype);
945  if (!tl)
946  return (title *)NULL;
947 
948  length = strlen(book->msg);
949  index = strtoint(book->msg);
950  for (t = tl->first_book; t; t = t->next)
951  if (t->size == length && t->msg_index == index) {
952 #ifdef ARCHIVE_DEBUG
953  LOG(llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
954 #endif
955  return t;
956  }
957 
958  return (title *)NULL;
959 }
960 
974 static void new_text_name(object *book, int msgtype) {
975  const char *name;
976 
977  if (book->type != BOOK)
978  return;
979 
980  switch (msgtype) {
981  case MSGTYPE_MONSTER:
983  break;
984 
985  case MSGTYPE_ARTIFACT:
987  break;
988 
989  case MSGTYPE_SPELLPATH:
991  break;
992 
993  case MSGTYPE_ALCHEMY:
995  break;
996 
997  case MSGTYPE_GODS:
999  break;
1000 
1001  case MSGTYPE_MSGFILE:
1002  default:
1003  if (book->weight > 2000) { /* based on weight */
1005  } else {
1007  }
1008  break;
1009  }
1010  free_string(book->name);
1011  book->name = add_string(name);
1012 }
1013 
1023 static void add_author(object *op, int msgtype) {
1024  char title[MAX_BUF];
1025  const char *name;
1026 
1027  if (msgtype < 0 || strlen(op->msg) < 5)
1028  return;
1029 
1030  switch (msgtype) {
1031  case MSGTYPE_MONSTER:
1033  break;
1034 
1035  case MSGTYPE_ARTIFACT:
1037  break;
1038 
1039  case MSGTYPE_SPELLPATH:
1041  break;
1042 
1043  case MSGTYPE_ALCHEMY:
1045  break;
1046 
1047  case MSGTYPE_GODS:
1049  break;
1050 
1051  case MSGTYPE_MSGFILE:
1052  default:
1054  }
1055 
1056  snprintf(title, sizeof(title), "of %s", name);
1057  op->title = add_string(title);
1058 }
1059 
1071 static int unique_book(const object *book, int msgtype) {
1072  title *test;
1073 
1074  if (!booklist)
1075  return 1; /* No archival entries! Must be unique! */
1076 
1077  /* Go through the booklist. If the author and name match, not unique so
1078  * return 0.
1079  */
1080  for (test = get_titlelist(msgtype)->first_book; test; test = test->next) {
1081  if (!strcmp(test->name, book->name) && !strcmp(book->title, test->authour))
1082  return 0;
1083  }
1084  return 1;
1085 }
1086 
1095 static void add_book_to_list(const object *book, int msgtype) {
1096  titlelist *tl = get_titlelist(msgtype);
1097  title *t;
1098 
1099  if (!tl) {
1100  LOG(llevError, "add_book_to_list can't get booklist!\n");
1101  return;
1102  }
1103 
1104  t = get_empty_book();
1105  t->name = add_string(book->name);
1106  t->authour = add_string(book->title);
1107  t->size = strlen(book->msg);
1108  t->msg_index = strtoint(book->msg);
1109  t->archname = add_string(book->arch->name);
1110  t->level = book->level;
1111 
1112  t->next = tl->first_book;
1113  tl->first_book = t;
1114  tl->number++;
1115 
1116  /* We have stuff we need to write now */
1118 
1119 #ifdef ARCHIVE_DEBUG
1120  LOG(llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
1121 #endif
1122 }
1123 
1137 static void change_book(object *book, int msgtype) {
1138  titlelist *tl;
1139  title *t;
1140  int tries;
1141 
1142  if (book->type != BOOK) {
1143  LOG(llevError, "change_book_name() called w/ illegal obj type.\n");
1144  return;
1145  }
1146 
1147  tl = get_titlelist(msgtype);
1148  t = NULL;
1149  tries = 0;
1150 
1151  /* look to see if our msg already been archived. If so, alter
1152  * the book to match the archival text. If we fail to match,
1153  * then we archive the new title/name/msg combo if there is
1154  * room on the titlelist.
1155  */
1156 
1157  if (strlen(book->msg) > 5 && (t = find_title(book, msgtype))) {
1158  object *tmpbook;
1159  sstring marker = object_get_value(book, "knowledge_marker");
1160 
1161  /* alter book properties */
1162  tmpbook = create_archetype(t->archname);
1163  if (marker != NULL)
1164  /* need to copy the knowledge_marker */
1165  object_set_value(tmpbook, "knowledge_marker", marker, 1);
1166  object_set_msg(tmpbook, book->msg);
1167  object_copy(tmpbook, book);
1168  object_free_drop_inventory(tmpbook);
1169 
1170  book->title = add_string(t->authour);
1171  free_string(book->name);
1172  book->name = add_string(t->name);
1173  book->level = t->level;
1174  } else { /* Don't have any default title, so lets make up a new one */
1175  int numb, maxnames = max_titles[msgtype];
1176  const char *old_title;
1177  const char *old_name;
1178 
1179  old_title = book->title ? add_string(book->title) : NULL;
1180  old_name = add_string(book->name);
1181 
1182  /* some pre-generated books have title already set (from
1183  * maps), also don't bother looking for unique title if
1184  * we already used up all the available names! */
1185 
1186  if (!tl) {
1187  LOG(llevError, "change_book_name(): can't find title list\n");
1188  numb = 0;
1189  } else
1190  numb = tl->number;
1191 
1192  if (numb == maxnames) {
1193 #ifdef ARCHIVE_DEBUG
1194  LOG(llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1195 #endif
1196  // Set tries to maximum. That way we get the descriptors on books when the
1197  // title set is full, too.
1198  tries = MAX_TITLE_CHECK;
1199  }
1200  /* shouldnt change map-maker books */
1201  else if (!book->title)
1202  do {
1203  /* random book name */
1204  new_text_name(book, msgtype);
1205  add_author(book, msgtype); /* random author */
1206  tries++;
1207  } while (!unique_book(book, msgtype) && tries < MAX_TITLE_CHECK);
1208 
1209  /* Now deal with 2 cases.
1210  * 1) If no space for a new title exists lets just restore
1211  * the old book properties. Remember, if the book had
1212  * matchd an older entry on the titlelist, we shouldnt
1213  * have called this routine in the first place!
1214  * 2) If we got a unique title, we need to add it to
1215  * the list.
1216  */
1217 
1218  if (tries == MAX_TITLE_CHECK) {
1219 #ifdef ARCHIVE_DEBUG
1220  LOG(llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1221 #endif
1222  /* restore old book properties here */
1223  free_string(book->name);
1224  if (book->title)
1225  free_string(book->title);
1226  book->title = old_title != NULL ? add_string(old_title) : NULL;
1227 
1228  if (RANDOM()%4) {
1229  /* Lets give the book a description to individualize it some */
1230  char new_name[MAX_BUF];
1231 
1232  snprintf(new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM()%arraysize(book_descrpt)], old_name);
1233  book->name = add_string(new_name);
1234  } else {
1235  book->name = add_string(old_name);
1236  }
1237  } else if (book->title && strlen(book->msg) > 5) { /* archive if long msg texts */
1238  add_book_to_list(book, msgtype);
1239  }
1240 
1241  if (old_title != NULL)
1242  free_string(old_title);
1243  free_string(old_name);
1244  }
1245 }
1246 
1247 /*****************************************************************************
1248  *
1249  * This is the start of the area that generates the actual contents
1250  * of the book.
1251  *
1252  *****************************************************************************/
1253 
1254 /*****************************************************************************
1255  * Monster msg generation code.
1256  ****************************************************************************/
1257 
1269 object *get_random_mon(int level) {
1270 
1271  /* safety check. Problem w/ init_mon_info list? */
1272  if (monsters.empty())
1273  return (object *)NULL;
1274 
1275  if (!level) {
1276  return monsters[RANDOM() % monsters.size()];
1277  }
1278 
1279  std::vector<object *> select;
1280  std::copy_if(monsters.cbegin(), monsters.cend(), std::back_inserter(select), [&] (auto ob) { return ob->level >= level; });
1281 
1282  if (select.empty()) {
1283  LOG(llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1284  return NULL;
1285  }
1286  return select[RANDOM() % select.size()];
1287 }
1288 
1298 static StringBuffer *mon_desc(const object *mon) {
1299  StringBuffer *desc = stringbuffer_new();
1300  stringbuffer_append_printf(desc, "\n---\n *** %s ***\n", mon->name);
1301  describe_item(mon, NULL, 0, desc);
1302  // If a monster has lore, print it here.
1303  if (mon->lore) {
1304  stringbuffer_append_printf(desc, "\n ^ %s", mon->lore);
1305  }
1306  return desc;
1307 }
1308 
1320 static object *get_next_mon(const object *tmp) {
1321  auto it = std::find(monsters.begin(), monsters.end(), tmp);
1322  if (it == monsters.end())
1323  return nullptr;
1324  ++it;
1325  if (it == monsters.end())
1326  it = monsters.begin();
1327 
1328  return *it;
1329 }
1330 
1343 static StringBuffer *mon_info_msg(int level, size_t booksize, object *book) {
1344  object *tmp;
1345  StringBuffer *marker = stringbuffer_new(), *desc = stringbuffer_new(), *mon = NULL;
1346  int added = 0;
1347  sstring final;
1348  const char *sep = ":";
1349 
1350  /*preamble */
1351  stringbuffer_append_string(desc, "This beastiary contains:");
1352  stringbuffer_append_string(marker, "monster");
1353 
1354  /* lets print info on as many monsters as will fit in our
1355  * document.
1356  * 8-96 Had to change this a bit, otherwise there would
1357  * have been an impossibly large number of combinations
1358  * of text! (and flood out the available number of titles
1359  * in the archive in a snap!) -b.t.
1360  */
1361  for (tmp = get_random_mon(level*3); tmp; tmp = get_next_mon(tmp)) {
1362  /* monster description */
1363  mon = mon_desc(tmp);
1364 
1365  if (stringbuffer_length(desc) + stringbuffer_length(mon) >= booksize)
1366  break;
1367  added++;
1368  stringbuffer_append_printf(marker, "%s%s", sep, tmp->arch->name);
1369  sep = "/";
1371  stringbuffer_delete(mon);
1372  mon = NULL;
1373  }
1374 
1375  if (mon != NULL) {
1376  stringbuffer_delete(mon);
1377  }
1378 
1379  final = stringbuffer_finish_shared(marker);
1380  if (added)
1381  object_set_value(book, "knowledge_marker", final, 1);
1382  free_string(final);
1383 
1384  return desc;
1385 }
1386 
1387 /*****************************************************************************
1388  * Artifact msg generation code.
1389  ****************************************************************************/
1390 
1400 static StringBuffer *artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator) {
1401  object *tmp;
1402  int chance;
1403  StringBuffer *desc = stringbuffer_new(), *sbuf;
1404 
1405  if (separator)
1406  stringbuffer_append_string(desc, "---\n");
1407 
1408  /* Name */
1409  if (!art->allowed.empty()) {
1410  archetype *arch;
1411  auto name = art->allowed[RANDOM() % art->allowed.size()];
1412  int inv = 0;
1413 
1414  if (name[0] == '!')
1415  inv = 1;
1416 
1418  arch = try_find_archetype(name + inv);
1419  if (!arch)
1420  arch = find_archetype_by_object_name(name + inv);
1421 
1422  if (!arch)
1423  LOG(llevError, "artifact_msg: missing archetype %s for artifact %s (type %d)\n", name + inv, art->item->name, art->item->type);
1424  else {
1425  if (inv)
1426  stringbuffer_append_printf(desc, " A %s (excepted %s) of %s", art_name_array[art_name].name, arch->clone.name_pl, art->item->name);
1427  else
1428  stringbuffer_append_printf(desc, " A %s of %s", arch->clone.name, art->item->name);
1429  }
1430  } else { /* default name is used */
1431  /* use the base 'generic' name for our artifact */
1432  stringbuffer_append_printf(desc, " The %s of %s", art_name_array[art_name].name, art->item->name);
1433  }
1434 
1435  /* chance of finding */
1436  stringbuffer_append_string(desc, " is ");
1437  chance = 100*((float)art->chance/al->total_chance);
1438  if (chance >= 20)
1439  stringbuffer_append_string(desc, "an uncommon");
1440  else if (chance >= 10)
1441  stringbuffer_append_string(desc, "an unusual");
1442  else if (chance >= 5)
1443  stringbuffer_append_string(desc, "a rare");
1444  else
1445  stringbuffer_append_string(desc, "a very rare");
1446 
1447  /* value of artifact */
1448  stringbuffer_append_printf(desc, " item with a value that is %d times normal.\n", art->item->value);
1449 
1450  /* include the message about the artifact, if exists, and book
1451  * level is kinda high */
1452  if (message && !(strlen(art->item->msg) > BOOK_BUF))
1453  stringbuffer_append_string(desc, art->item->msg);
1454 
1455  /* properties of the artifact */
1456  tmp = object_new();
1457  add_abilities(tmp, art->item);
1458  tmp->type = al->type;
1459  SET_FLAG(tmp, FLAG_IDENTIFIED);
1460  sbuf = describe_item(tmp, NULL, 0, NULL);
1461  if (stringbuffer_length(sbuf) > 1) {
1462  stringbuffer_append_string(desc, " Properties of this artifact include:\n ");
1464  stringbuffer_append_string(desc, "\n");
1465  }
1466  free(stringbuffer_finish(sbuf));
1468 
1469  return desc;
1470 }
1471 
1483 static StringBuffer *artifact_msg(unsigned int level, size_t booksize) {
1484  const artifactlist *al;
1485  const artifact *art;
1486  int i, type, index;
1487  int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
1489 
1490  /* values greater than 5 create msg buffers that are too big! */
1491  if (book_entries > 5)
1492  book_entries = 5;
1493 
1494  /* lets determine what kind of artifact type randomly.
1495  * Right now legal artifacts only come from those listed
1496  * in art_name_array. Also, we check to be sure an artifactlist
1497  * for that type exists!
1498  */
1499  i = 0;
1500  do {
1501  index = RANDOM()%arraysize(art_name_array);
1502  type = art_name_array[index].type;
1503  al = find_artifactlist(type);
1504  i++;
1505  } while (al == NULL && i < 10);
1506 
1507  if (i == 10) { /* Unable to find a message */
1509  return message;
1510  }
1511 
1512  /* There is no reason to start on the artifact list at the beginning. Lets
1513  * take our starting position randomly... */
1514  auto iart = al->items.cbegin();
1515  for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
1516  if (iart == al->items.cend())
1517  iart = al->items.cbegin(); /* hmm, out of stuff, loop back around */
1518  ++iart;
1519  }
1520 
1521  /* Ok, lets print out the contents */
1522  stringbuffer_append_printf(message, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1523 
1524  i = 0;
1525  /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1526  * as long as we have space up to the allowed max # (book_entires)
1527  */
1528  while (book_entries > 0) {
1529  int with_message;
1530  if (iart == al->items.cend())
1531  iart = al->items.cbegin();
1532  art = *iart;
1533  with_message = (art->item->msg && RANDOM()%4+1 < level) ? 1 : 0;
1534 
1535  desc = artifact_describe(art, al, with_message, index, i++);
1536 
1538  stringbuffer_delete(desc);
1539  break;
1540  }
1541 
1543  stringbuffer_delete(desc);
1544 
1545  ++iart;
1546  book_entries--;
1547  }
1548 
1549  return message;
1550 }
1551 
1552 /*****************************************************************************
1553  * Spellpath message generation
1554  *****************************************************************************/
1555 
1557 static struct {
1558  int prayers;
1559  int did_first_sp;
1560  uint32_t pnum;
1561  int level;
1562  size_t booksize;
1564  int done;
1568 static void do_spellpath_msg(archetype *at) {
1569  /* Determine if this is an appropriate spell. Must
1570  * be of matching path, must be of appropriate type (prayer
1571  * or not), and must be within the valid level range.
1572  */
1573  if (at->clone.type == SPELL
1574  && at->clone.path_attuned & sp_params.pnum
1575  && ((at->clone.stats.grace && sp_params.prayers) || (at->clone.stats.sp && !sp_params.prayers))
1576  && at->clone.level < sp_params.level*8) {
1577  if (strlen(at->clone.name) + stringbuffer_length(sp_params.buf) >= sp_params.booksize) {
1578  sp_params.done = 1;
1579  return;
1580  }
1581 
1582  if (sp_params.did_first_sp)
1584  sp_params.did_first_sp = 1;
1586  }
1587 }
1588 
1603  int path = RANDOM()%NRSPELLPATHS;
1604  sp_params.prayers = RANDOM()%2;
1605  sp_params.did_first_sp = 0;
1606  sp_params.pnum = spellpathdef[path];
1607  sp_params.done = 0;
1608 
1609  if (buf == NULL) {
1610  buf = stringbuffer_new();
1611  /* Preamble */
1612  stringbuffer_append_printf(buf, "Herein are detailed the names of %s", sp_params.prayers ? "prayers" : "incantations");
1613  stringbuffer_append_printf(buf, " belonging to the path of %s:\n ", spellpathnames[path]);
1614  }
1615  sp_params.level = level;
1616  sp_params.booksize = booksize;
1617  sp_params.buf = buf;
1618 
1620 
1621  /* Geez, no spells were generated. */
1622  if (!sp_params.did_first_sp) {
1623  if (RANDOM()%4) { /* usually, lets make a recursive call... */
1624  // If we do a recursive call, we reset the spell path, so we will want to reset our text as well.
1626  return spellpath_msg(level, booksize, NULL);
1627  }
1628  /* give up, cause knowing no spells exist for path is info too. need the header too. */
1629  stringbuffer_append_string(buf, "- no known spells exist -\n");
1630  }
1631  return buf;
1632 }
1633 
1642 static void make_formula_book(object *book, int level) {
1643  recipelist *fl;
1644  recipe *formula;
1645  int chance, count = 0;
1646  const char *op_name;
1647  archetype *at;
1648  StringBuffer *text, *title;
1649  char *final, km[MAX_BUF];
1650 
1651  /* the higher the book level, the more complex (ie number of
1652  * ingredients) the formula can be.
1653  */
1654  fl = get_formulalist((RANDOM()%level)/3+1);
1655  if (!fl)
1656  fl = get_formulalist(1); /* safety */
1657 
1658  if (fl->total_chance == 0) {
1659  object_set_msg(book, " <indecipherable text>\n");
1661  add_author(book, MSGTYPE_ALCHEMY);
1662  return;
1663  }
1664 
1665  /* get a random formula, weighted by its bookchance */
1666  chance = RANDOM()%fl->total_chance;
1667  for (formula = fl->items; formula != NULL; formula = formula->next) {
1668  chance -= formula->chance;
1669  if (chance <= 0 && formula->chance != 0 && !formula->is_combination)
1670  break;
1671  }
1672 
1673  if (!formula || formula->arch_names <= 0) {
1674  object_set_msg(book, " <indecipherable text>\n");
1676  add_author(book, MSGTYPE_ALCHEMY);
1677  return;
1678  }
1679 
1680  /* looks like a formula was found. Base the amount
1681  * of information on the booklevel and the spellevel
1682  * of the formula. */
1683 
1684  op_name = formula->arch_name[RANDOM()%formula->arch_names];
1685  at = find_archetype(op_name);
1686  if (at == (archetype *)NULL) {
1687  LOG(llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1688  object_set_msg(book, " <indecipherable text>\n");
1690  add_author(book, MSGTYPE_ALCHEMY);
1691  return;
1692  }
1693  op_name = at->clone.name;
1694 
1695  text = stringbuffer_new();
1696  title = stringbuffer_new();
1697 
1698  /* preamble */
1699  stringbuffer_append_printf(text, "Herein is described a%s %s project using %s:\n",
1700  formula->diff >= 10 && formula->diff < 15 ? "n" : "",
1702  formula->skill ? formula->skill : "an unknown skill");
1703 
1704  /* item name */
1705  if (strcmp(formula->title, "NONE")) {
1706  stringbuffer_append_printf(text, "The %s of %s", op_name, formula->title);
1707  /* This results in things like pile of philo. sulfur.
1708  * while philo. sulfur may look better, without this,
1709  * you get things like 'the wise' because its missing the
1710  * water of section.
1711  */
1713  } else {
1714  stringbuffer_append_printf(text, "The %s", op_name);
1716  if (at->clone.title) {
1719  }
1720  }
1721  /* Lets name the book something meaningful ! */
1722  if (book->name)
1723  free_string(book->name);
1725  if (book->title) {
1726  free_string(book->title);
1727  book->title = NULL;
1728  }
1729 
1730  /* ingredients to make it */
1731  if (formula->ingred != NULL) {
1732  linked_char *next;
1733  archetype *at;
1734  char name[MAX_BUF];
1735 
1736  at = find_archetype(formula->cauldron);
1737  if (at)
1738  query_name(&at->clone, name, MAX_BUF);
1739  else
1740  snprintf(name, sizeof(name), "an unknown place");
1741 
1742  stringbuffer_append_printf(text, " may be made at %s using the following ingredients:\n", name);
1743 
1744  for (next = formula->ingred; next != NULL; next = next->next) {
1745  count++;
1746  stringbuffer_append_printf(text, "%s\n", next->name);
1747  }
1748  } else {
1749  LOG(llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, formula->title);
1751  }
1752 
1753  final = stringbuffer_finish(text);
1754  object_set_msg(book, final);
1755  free(final);
1756 
1759  snprintf(km, sizeof(km), "alchemy:%d:%d:%s", count, formula->index, formula->title);
1760  object_set_value(book, "knowledge_marker", km, 1);
1761 }
1762 
1773 static StringBuffer *msgfile_msg(object *book, size_t booksize) {
1774  StringBuffer *ret = stringbuffer_new();
1775 
1776  GeneralMessage *msg = getManager()->messages()->random();
1777 
1778  if (msg && strlen(msg->message) <= booksize) {
1780  if (msg->identifier != NULL) {
1781  char km[HUGE_BUF];
1784  snprintf(km, sizeof(km), "message:%s", msg->identifier);
1785  object_set_value(book, "knowledge_marker", km, 1);
1786  }
1787  if (msg->quest_code) {
1788  /* add a 'apply' hook to launch the quest */
1789  archetype *at = find_archetype("quest_advance_apply");
1790  if (at != NULL) {
1791  object *event = object_create_arch(at);
1792  FREE_AND_COPY(event->name, msg->quest_code);
1793  object_insert_in_ob(event, book);
1794  }
1795  }
1796  } else {
1797 #ifdef BOOK_MSG_DEBUG
1798  // If msg was defined when we got here, we overflowed a book.
1799  if (msg)
1800  LOG(llevDebug, "Could not fit message %s into %s (%ld > %ld)\n", msg->identifier, book->name, strlen(msg->message), booksize);
1801 #endif
1802  stringbuffer_append_string(ret, "\n <undecipherable text>");
1803  }
1804 
1805  return ret;
1806 }
1807 
1822 static StringBuffer *god_info_msg(int level, size_t booksize, object *book) {
1823  int what = 0;
1824  const object *god = get_rand_god();
1825  StringBuffer *desc = NULL;
1826 
1827  if (!god)
1828  return NULL; /* oops, problems... */
1829 
1830  if (booksize > BOOK_BUF) {
1831  LOG(llevError, "common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (unsigned long)booksize, BOOK_BUF);
1832  booksize = BOOK_BUF;
1833  }
1834 
1835  if (level >= 2 && RANDOM()%2) {
1836  what |= GOD_ENEMY;
1837  }
1838  if (level >= 3 && RANDOM()%2) {
1839  what |= GOD_HOLYWORD;
1840  }
1841  if (level >= 4 && RANDOM()%2) {
1842  what |= GOD_RESISTANCES;
1843  }
1844  if (level >= 5 && RANDOM()%2) {
1845  what |= GOD_SACRED;
1846  }
1847  if (level >= 6 && RANDOM()%2) {
1848  what |= GOD_BLESSED;
1849  }
1850  if (level >= 8 && RANDOM()%2) {
1851  what |= GOD_IMMUNITIES;
1852  }
1853  if (level >= 12 && RANDOM()%2) {
1854  what |= GOD_PATHS;
1855  }
1856 
1857  desc = stringbuffer_new();
1858  what = describe_god(god, what, desc, booksize);
1859 
1860  /* check to be sure new buffer size dont exceed either
1861  * the maximum buffer size, or the 'natural' size of the
1862  * book... */
1863  if (stringbuffer_length(desc) > 1 && stringbuffer_length(desc) <= booksize) {
1864  char buf[BOOK_BUF];
1865  snprintf(buf, sizeof(buf), "god:%s:%d", god->name, what);
1866  object_set_value(book, "knowledge_marker", buf, 1);
1867  return desc;
1868  }
1869 
1870  stringbuffer_delete(desc);
1871  return NULL;
1872 }
1873 
1892 void tailor_readable_ob(object *book, int msg_type) {
1893  int level = book->level ? RANDOM()%book->level+1 : 1;
1894  size_t book_buf_size;
1895  StringBuffer *message = NULL;
1896 
1897  /* safety */
1898  if (book->type != BOOK)
1899  return;
1900 
1901  if (level <= 0)
1902  return; /* if no level no point in doing any more... */
1903 
1904  /* Max text length this book can have. */
1905  book_buf_size = BOOKSIZE(book);
1906  book_buf_size -= strlen("\n"); /* Keep enough for final \n. */
1907  assert(book_buf_size < BOOK_BUF);
1908 
1909  /* &&& The message switch &&& */
1910  /* Below all of the possible types of messages in the "book"s.
1911  */
1912  /*
1913  * IF you add a new type of book msg, you will have to do several things.
1914  * 1) make sure there is an entry in the msg switch below!
1915  * 2) make sure there is an entry in max_titles[] array.
1916  * 3) make sure there are entries for your case in new_text_title()
1917  * and add_authour().
1918  * 4) you may want separate authour/book name arrays in read.h
1919  */
1920 
1921  if (msg_type >= (int)arraysize(max_titles))
1922  msg_type = 0;
1923 
1924  msg_type = msg_type > 0 ? msg_type : (int)(RANDOM()%6);
1925  switch (msg_type) {
1926  case MSGTYPE_MONSTER:
1927  message = mon_info_msg(level, book_buf_size, book);
1928  break;
1929 
1930  case MSGTYPE_ARTIFACT:
1931  message = artifact_msg(level, book_buf_size);
1932  break;
1933 
1934  case MSGTYPE_SPELLPATH: /* grouping incantations/prayers by path */
1935  message = spellpath_msg(level, book_buf_size, NULL);
1936  break;
1937 
1938  case MSGTYPE_ALCHEMY: /* describe an alchemy formula */
1939  make_formula_book(book, level);
1940  /* make_formula_book already gives title */
1941  return;
1942  break;
1943 
1944  case MSGTYPE_GODS: /* bits of information about a god */
1945  message = god_info_msg(level, book_buf_size, book);
1946  break;
1947 
1948  case MSGTYPE_LIB: /* use info list in lib/ */
1949  default:
1950  message = msgfile_msg(book, book_buf_size);
1951  break;
1952  }
1953 
1954  if (message != NULL) {
1955  char *final;
1957  final = stringbuffer_finish(message);
1958  object_set_msg(book, final);
1959  free(final);
1960  /* lets give the "book" a new name, which may be a compound word */
1961  change_book(book, msg_type);
1962  }
1963 }
1964 
1965 /*****************************************************************************
1966  *
1967  * Cleanup routine for readable stuff.
1968  *
1969  *****************************************************************************/
1970 
1974 void free_all_readable(void) {
1975  titlelist *tlist, *tnext;
1976  title *title1, *titlenext;
1977 
1978  LOG(llevDebug, "freeing all book information\n");
1979 
1980  for (tlist = booklist; tlist != NULL; tlist = tnext) {
1981  tnext = tlist->next;
1982  for (title1 = tlist->first_book; title1; title1 = titlenext) {
1983  titlenext = title1->next;
1984  if (title1->name)
1985  free_string(title1->name);
1986  if (title1->authour)
1987  free_string(title1->authour);
1988  if (title1->archname)
1989  free_string(title1->archname);
1990  free(title1);
1991  }
1992  free(tlist);
1993  }
1994 }
1995 
1996 /*****************************************************************************
1997  *
1998  * Writeback routine for updating the bookarchive.
1999  *
2000  ****************************************************************************/
2001 
2006  FILE *fp;
2007  OutputFile of;
2008  int index;
2009  char fname[MAX_BUF];
2010  title *book;
2011  titlelist *bl;
2012 
2013  /* If nothing changed, don't write anything */
2015  return;
2016 
2017  snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
2018  LOG(llevDebug, "Updating book archive: %s...\n", fname);
2019 
2020  fp = of_open(&of, fname);
2021  if (fp == NULL)
2022  return;
2023 
2024  for (bl = get_titlelist(0), index = 0; bl; bl = bl->next, index++) {
2025  for (book = bl->first_book; book; book = book->next)
2026  if (book && book->authour) {
2027  fprintf(fp, "title %s\n", book->name);
2028  fprintf(fp, "authour %s\n", book->authour);
2029  fprintf(fp, "arch %s\n", book->archname);
2030  fprintf(fp, "level %d\n", book->level);
2031  fprintf(fp, "type %d\n", index);
2032  /* C89 doesn't have %zu... */
2033  fprintf(fp, "size %lu\n", (unsigned long)book->size);
2034  fprintf(fp, "index %d\n", book->msg_index);
2035  fprintf(fp, "end\n");
2036  }
2037  }
2038  if (!of_close(&of))
2039  return;
2040 
2041  if (chmod(fname, SAVE_MODE) != 0) {
2042  LOG(llevError, "Could not set permissions on '%s'\n", fname);
2043  }
2044 
2046 }
2047 
2056  uint8_t subtype = readable->subtype;
2057 
2058  if (subtype > last_readable_subtype)
2059  return &readable_message_types[0];
2060  return &readable_message_types[subtype];
2061 }
2062 
2069  return message->title;
2070 }
2071 
2078  return message->message;
2079 }
2080 
2087  return message->face;
2088 }
write_book_archive
void write_book_archive(void)
Write out the updated book archive to bookarch file.
Definition: readable.cpp:2005
PATH_TURNING
#define PATH_TURNING
Definition: spells.h:29
MSG_TYPE_MONUMENT_WALL_2
#define MSG_TYPE_MONUMENT_WALL_2
Definition: newclient.h:486
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
Face
New face structure - this enforces the notion that data is face by face only - you can not change the...
Definition: face.h:14
formula_book_name
static const char *const formula_book_name[]
Alchemy (formula) information.
Definition: readable.cpp:342
MSG_TYPE_BOOK_SPELL_PRAYER
#define MSG_TYPE_BOOK_SPELL_PRAYER
Definition: newclient.h:433
output_file.h
global.h
GOD_IMMUNITIES
#define GOD_IMMUNITIES
Write immunities.
Definition: god.h:18
change_book
static void change_book(object *book, int msgtype)
Give a new, fancier name to generated objects of type BOOK and SPELLBOOK.
Definition: readable.cpp:1137
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
path_book_name
static const char *const path_book_name[]
Book names for path information.
Definition: readable.cpp:173
stringbuffer_length
size_t stringbuffer_length(StringBuffer *sb)
Return the current length of the buffer.
Definition: stringbuffer.cpp:218
GeneralMessage
One general message, from the lib/messages file.
Definition: book.h:44
get_formulalist
recipelist * get_formulalist(int i)
Gets a formula list by ingredients count.
Definition: recipe.cpp:98
SAVE_MODE
#define SAVE_MODE
If you have defined SAVE_PLAYER, you might want to change this, too.
Definition: config.h:563
title::authour
const char * authour
the name of the book authour
Definition: readable.cpp:110
get_empty_booklist
static titlelist * get_empty_booklist(void)
Creates a titlelist.
Definition: readable.cpp:576
do_spellpath_msg
static void do_spellpath_msg(archetype *at)
Callback to write spells in messages.
Definition: readable.cpp:1568
mon_author
static const char *const mon_author[]
Used by monster beastuary texts.
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
Error, serious thing.
Definition: logger.h:11
init_mon_info
static void init_mon_info(void)
Creates the linked list of pointers to monster archetype objects if not called previously.
Definition: readable.cpp:886
GOD_PATHS
#define GOD_PATHS
Path information.
Definition: god.h:19
PATH_RESTORE
#define PATH_RESTORE
Definition: spells.h:21
object::path_attuned
uint32_t path_attuned
Paths the object is attuned to.
Definition: object.h:353
get_empty_book
static title * get_empty_book(void)
Creates a title.
Definition: readable.cpp:593
MSG_TYPE_PAPER_LETTER_OLD_2
#define MSG_TYPE_PAPER_LETTER_OLD_2
Definition: newclient.h:457
PATH_INFO
#define PATH_INFO
Definition: spells.h:26
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
arraysize
#define arraysize(arrayname)
Returns the element size of an array.
Definition: readable.cpp:98
MSG_TYPE_BOOK_SPELL_SUMMONER
#define MSG_TYPE_BOOK_SPELL_SUMMONER
Definition: newclient.h:436
book_author
static const char *const book_author[]
Used by 'generic' books.
Definition: readable.cpp:411
of_close
int of_close(OutputFile *of)
Closes an output file.
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
If set (any value), then monster is not listed in books.
Definition: object.h:596
free_all_readable
void free_all_readable(void)
Free all readable-related information.
Definition: readable.cpp:1974
AssetsManager::messages
Messages * messages()
Get messages.
Definition: AssetsManager.h:59
PATH_ELEC
#define PATH_ELEC
Definition: spells.h:16
monsters
static std::vector< object * > monsters
Information on monsters.
Definition: readable.cpp:142
of_open
FILE * of_open(OutputFile *of, const char *fname)
Opens an output file.
Definition: output_file.cpp:30
GLOVES
@ GLOVES
Definition: object.h:218
arttypename::name
const char * name
generic name to call artifacts of this type
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
Size of the arch_name[] array.
Definition: recipe.h:12
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:300
AssetsManager.h
spellpathnames
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.cpp:238
mon_book_name
static const char *const mon_book_name[]
Monster book information.
Definition: readable.cpp:261
stringbuffer_append_printf
void stringbuffer_append_printf(StringBuffer *sb, const char *format,...)
Append a formatted string to a string buffer instance.
Definition: stringbuffer.cpp:138
path_author
static const char *const path_author[]
Used by spellpath texts.
Definition: readable.cpp:183
artifact_msg
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.cpp:1483
MSG_TYPE_PAPER
#define MSG_TYPE_PAPER
Definition: newclient.h:400
MSG_TYPE_PAPER_LETTER_NEW_2
#define MSG_TYPE_PAPER_LETTER_NEW_2
Definition: newclient.h:459
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
MSG_TYPE_BOOK_QUARTO_1
#define MSG_TYPE_BOOK_QUARTO_1
Definition: newclient.h:430
PATH_SELF
#define PATH_SELF
Definition: spells.h:18
MSG_TYPE_SIGN_BASIC
#define MSG_TYPE_SIGN_BASIC
Definition: newclient.h:469
artifactlist::items
std::vector< artifact * > items
Artifacts for this type.
Definition: artifact.h:28
gods_book_name
static const char *const gods_book_name[]
God book information.
Definition: readable.cpp:304
ARMOUR
@ ARMOUR
Definition: object.h:125
MSG_TYPE_PAPER_SCROLL_NEW_2
#define MSG_TYPE_PAPER_SCROLL_NEW_2
Definition: newclient.h:465
WEAPON
@ WEAPON
Definition: object.h:124
MSG_TYPE_PAPER_SCROLL_OLD_2
#define MSG_TYPE_PAPER_SCROLL_OLD_2
Definition: newclient.h:463
MSG_TYPE_PAPER_NOTE_2
#define MSG_TYPE_PAPER_NOTE_2
Definition: newclient.h:454
MSG_TYPE_CARD_MONEY_2
#define MSG_TYPE_CARD_MONEY_2
Definition: newclient.h:449
MSG_TYPE_MONUMENT_STATUE_3
#define MSG_TYPE_MONUMENT_STATUE_3
Definition: newclient.h:481
artifact::item
object * item
Special values of the artifact.
Definition: artifact.h:15
god_info_msg
static StringBuffer * god_info_msg(int level, size_t booksize, object *book)
Generate a message detailing the properties of a random god.
Definition: readable.cpp:1822
add_abilities
void add_abilities(object *op, const object *change)
Apply artifact properties to an object.
Definition: artifact.cpp:320
AMULET
@ AMULET
Definition: object.h:144
recipelist::items
recipe * items
Pointer to first recipe in this list.
Definition: recipe.h:40
archetype::head
archetype * head
The main part of a linked object.
Definition: object.h:485
MSG_TYPE_PAPER_LETTER_OLD_1
#define MSG_TYPE_PAPER_LETTER_OLD_1
Definition: newclient.h:456
strtoktolin
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.cpp:684
MSG_TYPE_SIGN_DIR_RIGHT
#define MSG_TYPE_SIGN_DIR_RIGHT
Definition: newclient.h:471
gods_author
static const char *const gods_author[]
Used by gods texts.
Definition: readable.cpp:321
title::name
const char * name
the name of the book
Definition: readable.cpp:109
MSG_TYPE_CARD_SIMPLE_2
#define MSG_TYPE_CARD_SIMPLE_2
Definition: newclient.h:440
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
GeneralMessage::identifier
sstring identifier
Message identifier, can be NULL.
Definition: book.h:47
titlelist
Titles for one message type.
Definition: readable.cpp:121
object_copy
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.cpp:1192
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
artifact::allowed
std::vector< sstring > allowed
List of archetypes the artifact can affect.
Definition: artifact.h:18
MSG_TYPE_BOOK_CLASP_2
#define MSG_TYPE_BOOK_CLASP_2
Definition: newclient.h:427
MSG_TYPE_CARD
#define MSG_TYPE_CARD
Definition: newclient.h:399
prayers
int prayers
Definition: readable.cpp:1560
booksize
size_t booksize
Definition: readable.cpp:1564
MSGTYPE_MONSTER
#define MSGTYPE_MONSTER
Monster-related information.
Definition: readable.cpp:81
MSG_TYPE_BOOK_ELEGANT_1
#define MSG_TYPE_BOOK_ELEGANT_1
Definition: newclient.h:428
object::title
sstring title
Of foo, etc.
Definition: object.h:325
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
GOD_BLESSED
#define GOD_BLESSED
Write various information (resistances?).
Definition: god.h:17
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
buf
StringBuffer * buf
Definition: readable.cpp:1565
title::size
size_t size
size of the book message
Definition: readable.cpp:113
getManager
AssetsManager * getManager()
Definition: assets.cpp:304
object_insert_in_ob
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.cpp:2857
recipelist::total_chance
int total_chance
Total chance of the recipes in this list.
Definition: recipe.h:38
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
PATH_ABJURE
#define PATH_ABJURE
Definition: spells.h:20
readable_message_types
static const readable_message_type readable_message_types[]
Each line of this array is a readable subtype.
Definition: readable.cpp:485
GOD_HOLYWORD
#define GOD_HOLYWORD
Write holy word information.
Definition: god.h:14
titlelist::first_book
title * first_book
pointer to first book in this list
Definition: readable.cpp:123
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
linked_char
Definition: global.h:98
recipe::is_combination
int is_combination
Whather this is an alchemy recipe, or an item transformation description.
Definition: recipe.h:31
find_title
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.cpp:935
get_next_mon
static object * get_next_mon(const object *tmp)
This function returns the next monster after 'tmp' in the monster list.
Definition: readable.cpp:1320
MSG_TYPE_PAPER_SCROLL_OLD_1
#define MSG_TYPE_PAPER_SCROLL_OLD_1
Definition: newclient.h:462
need_to_write_bookarchive
static int need_to_write_bookarchive
If set then we have information to save.
Definition: readable.cpp:144
MSG_TYPE_CARD_STRANGE_1
#define MSG_TYPE_CARD_STRANGE_1
Definition: newclient.h:445
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)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
MSGTYPE_MSGFILE
#define MSGTYPE_MSGFILE
Message from the lib/messages file.
Definition: readable.cpp:91
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
add_author
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.cpp:1023
HELMET
@ HELMET
Definition: object.h:141
get_rand_god
const object * get_rand_god(void)
Returns a random god.
Definition: holy.cpp:73
object::subtype
uint8_t subtype
Subtype of object.
Definition: object.h:349
linked_char::name
const char * name
Definition: global.h:99
recipelist
List of recipes with a certain number of ingredients.
Definition: recipe.h:37
MSG_TYPE_MONUMENT_GRAVESTONE_1
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
Definition: newclient.h:482
PATH_WOUNDING
#define PATH_WOUNDING
Definition: spells.h:30
MSG_TYPE_MONUMENT
#define MSG_TYPE_MONUMENT
Definition: newclient.h:402
PATH_CREATE
#define PATH_CREATE
Definition: spells.h:24
MSG_TYPE_CARD_STRANGE_2
#define MSG_TYPE_CARD_STRANGE_2
Definition: newclient.h:446
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
MSG_TYPE_SIGN_DIR_BOTH
#define MSG_TYPE_SIGN_DIR_BOTH
Definition: newclient.h:472
MSG_TYPE_MONUMENT_GRAVESTONE_2
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
Definition: newclient.h:483
get_titlelist
static titlelist * get_titlelist(int i)
Gets the ith titlelist.
Definition: readable.cpp:611
PATH_DETONATE
#define PATH_DETONATE
Definition: spells.h:22
stringbuffer_finish_shared
sstring stringbuffer_finish_shared(StringBuffer *sb)
Deallocate the string buffer instance and return the string as a shared string.
Definition: stringbuffer.cpp:85
MSG_TYPE_SIGN_DIR_LEFT
#define MSG_TYPE_SIGN_DIR_LEFT
Definition: newclient.h:470
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
MSG_TYPE_BOOK_CLASP_1
#define MSG_TYPE_BOOK_CLASP_1
Definition: newclient.h:426
book_descrpt
static const char *const book_descrpt[]
Book descriptions.
Definition: readable.cpp:458
ROD
@ ROD
Definition: object.h:114
init_readable
void init_readable(void)
Initialize linked lists utilized by message functions in tailor_readable_ob()
Definition: readable.cpp:904
titlelist::next
titlelist * next
pointer to next book list
Definition: readable.cpp:124
done
int done
Definition: readable.cpp:1566
init_book_archive
static void init_book_archive(void)
If not called before, initialize the info list.
Definition: readable.cpp:738
tailor_readable_ob
void tailor_readable_ob(object *book, int msg_type)
The main routine.
Definition: readable.cpp:1892
spellpath_msg
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.cpp:1602
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
FREE_AND_COPY
#define FREE_AND_COPY(sv, nv)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:206
MSG_TYPE_MONUMENT_STATUE_2
#define MSG_TYPE_MONUMENT_STATUE_2
Definition: newclient.h:480
add_book_to_list
static void add_book_to_list(const object *book, int msgtype)
Adds a book to the list of existing books.
Definition: readable.cpp:1095
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
message
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your message
Definition: survival-guide.txt:34
PATH_SUMMON
#define PATH_SUMMON
Definition: spells.h:19
MSG_TYPE_CARD_ELEGANT_1
#define MSG_TYPE_CARD_ELEGANT_1
Definition: newclient.h:442
recipe::index
int index
Index value derived from formula ingredients.
Definition: recipe.h:18
t
in that case they will be relative to whatever the PWD of the crossfire server process is You probably shouldn t
Definition: server-directories.txt:28
object_create_arch
object * object_create_arch(archetype *at)
Create a full object using the given archetype.
Definition: arch.cpp:296
book.h
MAX_TITLE_CHECK
#define MAX_TITLE_CHECK
How many times to try to generate a unique name for a book.
Definition: readable.cpp:76
linked_char::next
struct linked_char * next
Definition: global.h:100
title
Information on one title.
Definition: readable.cpp:108
artifactlist
This represents all archetypes for one particular object type.
Definition: artifact.h:24
arttypename
special structure, used only by art_name_array[]
Definition: readable.cpp:128
PATH_TRANSFER
#define PATH_TRANSFER
Definition: spells.h:28
FLAG_UNAGGRESSIVE
#define FLAG_UNAGGRESSIVE
Monster doesn't attack players.
Definition: define.h:272
MSG_TYPE_CARD_ELEGANT_3
#define MSG_TYPE_CARD_ELEGANT_3
Definition: newclient.h:444
artifact_describe
static StringBuffer * artifact_describe(const artifact *art, const artifactlist *al, int message, int art_name, int separator)
Describe an artifact.
Definition: readable.cpp:1400
PATH_FROST
#define PATH_FROST
Definition: spells.h:15
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
MSG_TYPE_CARD_MONEY_3
#define MSG_TYPE_CARD_MONEY_3
Definition: newclient.h:450
MSG_TYPE_BOOK_SPELL_EVOKER
#define MSG_TYPE_BOOK_SPELL_EVOKER
Definition: newclient.h:432
ARROW
@ ARROW
Definition: object.h:122
MSG_TYPE_MONUMENT_GRAVESTONE_3
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
Definition: newclient.h:484
living::sp
int16_t sp
Spell points.
Definition: living.h:42
get_message_body
sstring get_message_body(const GeneralMessage *message)
Get a message's body.
Definition: readable.cpp:2077
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
MSG_TYPE_MONUMENT_STONE_3
#define MSG_TYPE_MONUMENT_STONE_3
Definition: newclient.h:478
MSG_TYPE_MONUMENT_WALL_3
#define MSG_TYPE_MONUMENT_WALL_3
Definition: newclient.h:487
titlelist::number
int number
number of items in the list
Definition: readable.cpp:122
BOOK
@ BOOK
Definition: object.h:119
trim
const char * trim(const char *buf)
Return buf without its leading spaces.
Definition: readable.cpp:661
MSG_TYPE_PAPER_ENVELOPE_2
#define MSG_TYPE_PAPER_ENVELOPE_2
Definition: newclient.h:461
MSG_TYPE_CARD_ELEGANT_2
#define MSG_TYPE_CARD_ELEGANT_2
Definition: newclient.h:443
MSG_TYPE_PAPER_NOTE_1
#define MSG_TYPE_PAPER_NOTE_1
Definition: newclient.h:453
RING
@ RING
Definition: object.h:190
MSG_TYPE_BOOK_SPELL_SORCERER
#define MSG_TYPE_BOOK_SPELL_SORCERER
Definition: newclient.h:435
MSG_TYPE_BOOK_SPELL_PYRO
#define MSG_TYPE_BOOK_SPELL_PYRO
Definition: newclient.h:434
PATH_TRANSMUTE
#define PATH_TRANSMUTE
Definition: spells.h:27
title::archname
const char * archname
the archetype name of the book
Definition: readable.cpp:111
MSGTYPE_GODS
#define MSGTYPE_GODS
God-related information.
Definition: readable.cpp:89
MSG_TYPE_SIGN_MAGIC_MOUTH
#define MSG_TYPE_SIGN_MAGIC_MOUTH
Definition: newclient.h:473
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
fatal
void fatal(enum fatal_error err)
fatal() is meant to be called whenever a fatal signal is intercepted.
Definition: utils.cpp:590
mon_desc
static StringBuffer * mon_desc(const object *mon)
Returns a description of the monster.
Definition: readable.cpp:1298
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
object_new
object * object_new(void)
Grabs an object from the list of unused objects, makes sure it is initialised, and returns it.
Definition: object.cpp:1273
describe_item
StringBuffer * describe_item(const object *op, const object *owner, int use_media_tags, StringBuffer *buf)
Describes an item, in all its details.
Definition: item.cpp:951
create_archetype
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.cpp:276
path
pluglist shows those as well as a short text describing each the list will simply appear empty The keyword for the Python plugin is Python plugout< keyword > Unloads a given identified by its _keyword_ So if you want to unload the Python you need to do plugout Python plugin< libname > Loads a given whose _filename_ is libname So in the case of you d have to do a plugin cfpython so Note that all filenames are relative to the default plugin path(SHARE/plugins). Console messages. ----------------- When Crossfire starts
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
RANDOM
#define RANDOM()
Definition: define.h:638
arttypename::type
int type
matching type
Definition: readable.cpp:130
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
PATH_DEATH
#define PATH_DEATH
Definition: spells.h:31
recipe
One alchemy recipe.
Definition: recipe.h:10
art_book_name
static const char *const art_book_name[]
Book titles for artifact information.
Definition: readable.cpp:227
GeneralMessage::message
sstring message
The message's body.
Definition: book.h:49
GOD_RESISTANCES
#define GOD_RESISTANCES
Write resistances.
Definition: god.h:15
MSG_TYPE_CARD_MONEY_1
#define MSG_TYPE_CARD_MONEY_1
Definition: newclient.h:448
object::lore
sstring lore
Obscure information about this object, to get put into books and the like.
Definition: object.h:332
PATH_TELE
#define PATH_TELE
Definition: spells.h:25
llevInfo
@ llevInfo
Information.
Definition: logger.h:12
find_archetype_by_object_name
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.cpp:51
MSG_TYPE_PAPER_ENVELOPE_1
#define MSG_TYPE_PAPER_ENVELOPE_1
Definition: newclient.h:460
spells.h
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
get_message_title
sstring get_message_title(const GeneralMessage *message)
Get a message's title.
Definition: readable.cpp:2068
did_first_sp
int did_first_sp
Definition: readable.cpp:1561
MSGTYPE_LIB
#define MSGTYPE_LIB
Message from the lib/messages file.
Definition: readable.cpp:79
MSG_TYPE_CARD_SIMPLE_3
#define MSG_TYPE_CARD_SIMPLE_3
Definition: newclient.h:441
spellpathdef
static const uint32_t spellpathdef[NRSPELLPATHS]
Spellpath information.
Definition: readable.cpp:149
stringbuffer_delete
void stringbuffer_delete(StringBuffer *sb)
Totally delete a string buffer.
Definition: stringbuffer.cpp:71
msgfile_msg
static StringBuffer * msgfile_msg(object *book, size_t booksize)
Generate a message drawn randomly from lib/messages.
Definition: readable.cpp:1773
PATH_PROT
#define PATH_PROT
Definition: spells.h:13
recipe::chance
int chance
Chance that recipe for this item will appear in an alchemical grimore.
Definition: recipe.h:14
artifact::chance
uint16_t chance
Chance of the artifact to happen.
Definition: artifact.h:16
MSGTYPE_ALCHEMY
#define MSGTYPE_ALCHEMY
Alchemy-related information.
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:458
find_archetype
archetype * find_archetype(const char *name)
Definition: assets.cpp:265
MSG_TYPE_BOOK_ELEGANT_2
#define MSG_TYPE_BOOK_ELEGANT_2
Definition: newclient.h:429
strtoint
int strtoint(const char *buf)
Convert buf into an integer equal to the coadded sum of the (lowercase) character.
Definition: recipe.cpp:709
GOD_ENEMY
#define GOD_ENEMY
Write down god's 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)
Set the message field of an object.
Definition: object.cpp:4811
recipe::diff
int diff
Alchemical dfficulty level.
Definition: recipe.h:16
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
BOOK_BUF
#define BOOK_BUF
Maximum message buf size for books.
Definition: book.h:16
title::next
title * next
next item in the list
Definition: readable.cpp:115
assets.h
artifactlist::total_chance
uint16_t total_chance
Sum of chance for are artifacts on this list.
Definition: artifact.h:26
MSGTYPE_ARTIFACT
#define MSGTYPE_ARTIFACT
Artifact-related information.
Definition: readable.cpp:83
do_monster
static void do_monster(archetype *at)
Definition: readable.cpp:874
art_name_array
static const arttypename art_name_array[]
Artiface/item information.
Definition: readable.cpp:207
text
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended text
Definition: media-tags.txt:35
MSG_TYPE_MONUMENT_STONE_2
#define MSG_TYPE_MONUMENT_STONE_2
Definition: newclient.h:477
stringbuffer_append_stringbuffer
void stringbuffer_append_stringbuffer(StringBuffer *sb, const StringBuffer *sb2)
Append the contents of a string buffer instance to another string buffer instance.
Definition: stringbuffer.cpp:165
new_text_name
static void new_text_name(object *book, int msgtype)
Only for objects of type BOOK.
Definition: readable.cpp:974
heavy_book_name
static const char *const heavy_book_name[]
Name for big books.
Definition: readable.cpp:397
level
int level
Definition: readable.cpp:1563
MSGTYPE_SPELLPATH
#define MSGTYPE_SPELLPATH
Spellpath-related information.
Definition: readable.cpp:85
readable_message_type
Struct to store the message_type and message_subtype for signs and books used by the player.
Definition: book.h:36
formula_author
static const char *const formula_author[]
This isn't used except for empty books.
Definition: readable.cpp:356
booklist
static titlelist * booklist
Buffer of books read in from the bookarch file.
Definition: readable.cpp:139
MSG_TYPE_MONUMENT_STATUE_1
#define MSG_TYPE_MONUMENT_STATUE_1
Definition: newclient.h:479
title::level
unsigned int level
level of difficulty of this message
Definition: readable.cpp:112
MSG_TYPE_MONUMENT_WALL_1
#define MSG_TYPE_MONUMENT_WALL_1
Definition: newclient.h:485
get_readable_message_type
const readable_message_type * get_readable_message_type(object *readable)
Get the readable type for an object (hopefully book).
Definition: readable.cpp:2055
art_author
static const char *const art_author[]
Used by artifact texts.
Definition: readable.cpp:245
last_readable_subtype
static const int last_readable_subtype
Number of elements in readable_message_types.
Definition: readable.cpp:549
get_random_mon
object * get_random_mon(int level)
Returns a random monster selected from linked list of all monsters in the current game.
Definition: readable.cpp:1269
book_overflow
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
Checks if buf1 and buf2 can be combined.
Definition: readable.cpp:719
FOOD
@ FOOD
Definition: object.h:117
MSG_TYPE_PAPER_NOTE_3
#define MSG_TYPE_PAPER_NOTE_3
Definition: newclient.h:455
MSG_TYPE_BOOK_QUARTO_2
#define MSG_TYPE_BOOK_QUARTO_2
Definition: newclient.h:431
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:269
mon_info_msg
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.cpp:1343
unique_book
static int unique_book(const object *book, int msgtype)
Check to see if the book title/msg is unique.
Definition: readable.cpp:1071
recipe::ingred
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
MSG_TYPE_CARD_SIMPLE_1
#define MSG_TYPE_CARD_SIMPLE_1
Definition: newclient.h:439
light_book_name
static const char *const light_book_name[]
Generic book information.
Definition: readable.cpp:378
MSG_TYPE_MONUMENT_STONE_1
#define MSG_TYPE_MONUMENT_STONE_1
Definition: newclient.h:476
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
recipe::next
recipe * next
Next recipe with the same number of ingredients.
Definition: recipe.h:24
chance
bool chance(int a, int b)
Return true with a probability of a/b.
Definition: treasure.cpp:866
recipe::skill
sstring skill
Skill name used to make this recipe.
Definition: recipe.h:26
living::grace
int16_t grace
Grace.
Definition: living.h:44
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
MSG_TYPE_SIGN
#define MSG_TYPE_SIGN
Definition: newclient.h:401
MSG_TYPE_BOOK
#define MSG_TYPE_BOOK
Definition: newclient.h:398
artifact
This is one artifact, ie one special item.
Definition: artifact.h:14
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.cpp:4499
player::title
char title[BIG_NAME]
Default title, like fighter, wizard, etc.
Definition: player.h:184
buf_overflow
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
We don't want to exceed the buffer size of buf1 by adding on buf2!
Definition: shstr.cpp:398
describe_god
int describe_god(const object *god, int what, StringBuffer *buf, size_t maxlen)
Describe a god.
Definition: holy.cpp:109
it
if you malloc the data for the make sure to free it when done There is also the newclient h file which is shared between the client and server This file contains the definition of the as well as many defined values for constants of varying you will need to grab these constant values for yourself Many of the constants in this file are used in the protocol to denote types Image Caching ~ Image caching has been implemented on the with necessary server support to handle it This section will briefly describe how image caching works on the protocol as well as how the current client does it the client checks for an option denoting the image caching is desired If we initialize all the images to a default value this means we don t need to put special checks into the drawing code to see if we have an image we just draw the default we know what filename to store it as we request the server to do image caching This is done by or ing the cache directive to the image mode we want C when the server finds an image number that it has not send to the it sends us a name command information us the number to name and there is no space between that the and the name Such formating is difficult but the above example illustrates the data is sent The client then checks for the existence of the image locally It is up to the client to organize images and then splits them into sub directories based on the first letters in the above the file would be crossfire images CS CSword If the client does not have the image or otherwise needs a copy from the it then requests it
Definition: protocol.txt:2158
add_book
static void add_book(title *book, int type, const char *fname, int lineno)
Appends a book to the booklist.
Definition: readable.cpp:860
MSG_TYPE_PAPER_SCROLL_MAGIC
#define MSG_TYPE_PAPER_SCROLL_MAGIC
Definition: newclient.h:466
BOOTS
@ BOOTS
Definition: object.h:217
make_formula_book
static void make_formula_book(object *book, int level)
Generate a message detailing the properties of a randomly selected alchemical formula.
Definition: readable.cpp:1642
FLAG_CHANGING
#define FLAG_CHANGING
Changes to other_arch when anim is done.
Definition: define.h:263
title::msg_index
int msg_index
an index value derived from book message
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:464
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)
Get the book buffer size for an individual book object.
Definition: book.h:31
max_titles
static const int max_titles[6]
Number of titles for different name lists.
Definition: readable.cpp:552
nstrtok
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.cpp:642
living.h
find_artifactlist
artifactlist * find_artifactlist(int type)
Finds the artifact list for a certain item type.
Definition: artifact.cpp:574
artifactlist::type
uint8_t type
Object type that this list represents.
Definition: artifact.h:25
MSG_TYPE_CARD_STRANGE_3
#define MSG_TYPE_CARD_STRANGE_3
Definition: newclient.h:447
get_message_face
const Face * get_message_face(const GeneralMessage *message)
Get a message's face.
Definition: readable.cpp:2086
pnum
uint32_t pnum
Definition: readable.cpp:1562
recipe_get_difficulty_string
const char * recipe_get_difficulty_string(int difficulty)
A method to produce a difficulty adjective to describe alchemy projects.
Definition: recipe.cpp:962
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
GeneralMessage::quest_code
sstring quest_code
Optional quest code and state this message will start.
Definition: book.h:50
NRSPELLPATHS
#define NRSPELLPATHS
Number of spell paths.
Definition: spells.h:40
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
GOD_SACRED
#define GOD_SACRED
Write sacred creatures.
Definition: god.h:16
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
OutputFile
Definition: output_file.h:41
recipe::cauldron
sstring cauldron
Arch of the cauldron/workbench used to house the formulae.
Definition: recipe.h:27
recipe::title
sstring title
Distinguishing name of product.
Definition: recipe.h:11
Settings::localdir
const char * localdir
Read/write data files.
Definition: global.h:251