00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00038
00039
00040 #include <stdio.h>
00041 #include <global.h>
00042 #include <book.h>
00043 #include <living.h>
00044 #include <spells.h>
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00082 #define MAX_TITLE_CHECK 20
00083
00084 #define MSGTYPE_LIB 0
00085 #define MSGTYPE_MONSTER 1
00086 #define MSGTYPE_ARTIFACT 2
00087 #define MSGTYPE_SPELLPATH 3
00088 #define MSGTYPE_ALCHEMY 4
00089 #define MSGTYPE_GODS 5
00090 #define MSGTYPE_MSGFILE 6
00091
00097 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
00098
00099
00100
00101
00102
00104 typedef struct titlestruct {
00105 const char *name;
00106 const char *authour;
00107 const char *archname;
00108 int level;
00109 size_t size;
00110 int msg_index;
00111 struct titlestruct *next;
00112 } title;
00113
00114 typedef struct titleliststruct {
00115 int number;
00116 struct titlestruct *first_book;
00117 struct titleliststruct *next;
00118 } titlelist;
00119
00121 typedef struct namebytype {
00122 const char *name;
00123 int type;
00124 } arttypename;
00125
00126 static void add_book(title *book, int type, const char *fname, int lineno);
00127
00132 static titlelist *booklist = NULL;
00133
00135 static objectlink *first_mon_info = NULL;
00136
00141 static int nrofmon = 0, need_to_write_bookarchive = 0;
00142
00147 static int nrofmsg = 0;
00148
00153 static linked_char *first_msg = NULL;
00154
00158 static const uint32 spellpathdef[NRSPELLPATHS] = {
00159 PATH_PROT,
00160 PATH_FIRE,
00161 PATH_FROST,
00162 PATH_ELEC,
00163 PATH_MISSILE,
00164 PATH_SELF,
00165 PATH_SUMMON,
00166 PATH_ABJURE,
00167 PATH_RESTORE,
00168 PATH_DETONATE,
00169 PATH_MIND,
00170 PATH_CREATE,
00171 PATH_TELE,
00172 PATH_INFO,
00173 PATH_TRANSMUTE,
00174 PATH_TRANSFER,
00175 PATH_TURNING,
00176 PATH_WOUNDING,
00177 PATH_DEATH,
00178 PATH_LIGHT
00179 };
00180
00182 static const char *const path_book_name[] = {
00183 "codex",
00184 "compendium",
00185 "exposition",
00186 "tables",
00187 "treatise"
00188 };
00189
00191 static const char *const path_author[] = {
00192 "aether",
00193 "astral byways",
00194 "connections",
00195 "the Grey Council",
00196 "deep pathways",
00197 "knowledge",
00198 "magic",
00199 "mystic ways",
00200 "pathways",
00201 "power",
00202 "spells",
00203 "transforms",
00204 "the mystic veil",
00205 "unknown spells"
00206 };
00207
00214 static const arttypename art_name_array[] = {
00215 { "Helmet", HELMET },
00216 { "Amulet", AMULET },
00217 { "Shield", SHIELD },
00218 { "Bracers", BRACERS },
00219 { "Boots", BOOTS },
00220 { "Cloak", CLOAK },
00221 { "Gloves", GLOVES },
00222 { "Gridle", GIRDLE },
00223 { "Ring", RING },
00224 { "Horn", HORN },
00225 { "Missile Weapon", BOW },
00226 { "Missile", ARROW },
00227 { "Hand Weapon", WEAPON },
00228 { "Artifact", SKILL },
00229 { "Food", FOOD },
00230 { "Body Armour", ARMOUR }
00231 };
00232
00234 static const char *const art_book_name[] = {
00235 "collection",
00236 "file",
00237 "files",
00238 "guide",
00239 "handbook",
00240 "index",
00241 "inventory",
00242 "list",
00243 "listing",
00244 "record",
00245 "record book"
00246 };
00247
00249 static const char *const art_author[] = {
00250 "ancient things",
00251 "artifacts",
00252 "Havlor",
00253 "items",
00254 "lost artifacts",
00255 "the ancients",
00256 "useful things"
00257 };
00258
00262 static const char *const mon_book_name[] = {
00263 "beastuary",
00264 "catalog",
00265 "compilation",
00266 "collection",
00267 "encyclopedia",
00268 "guide",
00269 "handbook",
00270 "list",
00271 "manual",
00272 "notes",
00273 "record",
00274 "register",
00275 "volume"
00276 };
00277
00279 static const char *const mon_author[] = {
00280 "beasts",
00281 "creatures",
00282 "dezidens",
00283 "dwellers",
00284 "evil nature",
00285 "life",
00286 "monsters",
00287 "nature",
00288 "new life",
00289 "residents",
00290 "the spawn",
00291 "the living",
00292 "things"
00293 };
00294
00298 static const char *const gods_book_name[] = {
00299 "devotional",
00300 "devout notes",
00301 "divine text",
00302 "divine work",
00303 "holy book",
00304 "holy record",
00305 "moral text",
00306 "sacred guide",
00307 "testament",
00308 "transcript"
00309 };
00310
00312 static const char *const gods_author[] = {
00313 "cults",
00314 "joy",
00315 "lasting curse",
00316 "madness",
00317 "religions",
00318 "the dead",
00319 "the gods",
00320 "the heirophant",
00321 "the poor priest",
00322 "the priestess",
00323 "pain",
00324 "white"
00325 };
00326
00330 static const char *const formula_book_name[] = {
00331 "cookbook",
00332 "formulary",
00333 "lab book",
00334 "lab notes",
00335 "recipe book",
00336 "experiment record",
00337 "work plan",
00338 "design notes"
00339 };
00340
00342 static const char *const formula_author[] = {
00343 "Albertus Magnus",
00344 "alchemy",
00345 "balms",
00346 "creation",
00347 "dusts",
00348 "magical manufacture",
00349 "making",
00350 "philosophical items",
00351 "potions",
00352 "powders",
00353 "the cauldron",
00354 "the lamp black",
00355 "transmutation",
00356 "waters"
00357 };
00358
00364 static const char *const light_book_name[] = {
00365 "calendar",
00366 "datebook",
00367 "diary",
00368 "guidebook",
00369 "handbook",
00370 "ledger",
00371 "notes",
00372 "notebook",
00373 "octavo",
00374 "pamphlet",
00375 "practicum",
00376 "script",
00377 "transcript"
00378 };
00379
00381 static const char *const heavy_book_name[] = {
00382 "catalog",
00383 "compendium",
00384 "guide",
00385 "manual",
00386 "opus",
00387 "tome",
00388 "treatise",
00389 "volume",
00390 "work"
00391 };
00392
00394 static const char *const book_author[] = {
00395 "Abdulah",
00396 "Al'hezred",
00397 "Alywn",
00398 "Arundel",
00399 "Arvind",
00400 "Aerlingas",
00401 "Bacon",
00402 "Baliqendii",
00403 "Bosworth",
00404 "Beathis",
00405 "Bertil",
00406 "Cauchy",
00407 "Chakrabarti",
00408 "der Waalis",
00409 "Dirk",
00410 "Djwimii",
00411 "Eisenstaadt",
00412 "Fendris",
00413 "Frank",
00414 "Habbi",
00415 "Harlod",
00416 "Ichibod",
00417 "Janus",
00418 "June",
00419 "Magnuson",
00420 "Nandii",
00421 "Nitfeder",
00422 "Norris",
00423 "Parael",
00424 "Penhew",
00425 "Sophia",
00426 "Skilly",
00427 "Tahir",
00428 "Thockmorton",
00429 "Thomas",
00430 "van Helsing",
00431 "van Pelt",
00432 "Voormis",
00433 "Xavier",
00434 "Xeno",
00435 "Zardoz",
00436 "Zagy"
00437 };
00438
00440 static const char *const book_descrpt[] = {
00441 "ancient",
00442 "cryptic",
00443 "cryptical",
00444 "dusty",
00445 "hiearchical",
00446 "grizzled",
00447 "gold-guilt",
00448 "great",
00449 "lost",
00450 "magnificent",
00451 "musty",
00452 "mythical",
00453 "mystical",
00454 "rustic",
00455 "stained",
00456 "silvered",
00457 "transcendental",
00458 "weathered"
00459 };
00460
00467 static const readable_message_type readable_message_types[] = {
00468 { 0, 0 },
00469
00470 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1 },
00471 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_2 },
00472 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_1 },
00473 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_2 },
00474 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_1 },
00475 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_2 },
00476 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_EVOKER },
00477 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PRAYER },
00478 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PYRO },
00479 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER },
00480 { MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SUMMONER },
00481
00482 { MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_1 },
00483 { MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_2 },
00484 { MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_3 },
00485 { MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_1 },
00486 { MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_2 },
00487 { MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_3 },
00488 { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_1 },
00489 { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_2 },
00490 { MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3 },
00491 { MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_1 },
00492 { MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_2 },
00493 { MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_3 },
00494
00495
00496 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_1 },
00497 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_2 },
00498 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_3 },
00499 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_1 },
00500 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_2 },
00501 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_1 },
00502 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2 },
00503 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_1 },
00504 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_2 },
00505 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_1 },
00506 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_2 },
00507 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_1 },
00508 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_2 },
00509 { MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_MAGIC },
00510
00511
00512 { MSG_TYPE_SIGN, MSG_TYPE_SIGN_BASIC },
00513 { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_LEFT },
00514 { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT },
00515 { MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_BOTH },
00516
00517
00518 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_1 },
00519 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_2 },
00520 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_3 },
00521 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_1 },
00522 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_2 },
00523 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_3 },
00524 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_1 },
00525 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_2 },
00526 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_3 },
00527 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_1 },
00528 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_2 },
00529 { MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_3 }
00530 };
00531
00533 static const int last_readable_subtype = arraysize(readable_message_types);
00534
00536 static const int max_titles[6] = {
00537 (arraysize(light_book_name)+arraysize(heavy_book_name))*arraysize(book_author),
00538 arraysize(mon_book_name)*arraysize(mon_author),
00539 arraysize(art_book_name)*arraysize(art_author),
00540 arraysize(path_book_name)*arraysize(path_author),
00541 arraysize(formula_book_name)*arraysize(formula_author),
00542 arraysize(gods_book_name)*arraysize(gods_author),
00543 };
00544
00545
00546
00547
00548
00549
00550
00560 static titlelist *get_empty_booklist(void) {
00561 titlelist *bl = (titlelist *)malloc(sizeof(titlelist));
00562
00563 if (bl == NULL)
00564 fatal(OUT_OF_MEMORY);
00565 bl->number = 0;
00566 bl->first_book = NULL;
00567 bl->next = NULL;
00568 return bl;
00569 }
00570
00580 static title *get_empty_book(void) {
00581 title *t = (title *)malloc(sizeof(title));
00582
00583 if (t == NULL)
00584 fatal(OUT_OF_MEMORY);
00585 t->name = NULL;
00586 t->archname = NULL;
00587 t->authour = NULL;
00588 t->level = 0;
00589 t->size = 0;
00590 t->msg_index = 0;
00591 t->next = NULL;
00592 return t;
00593 }
00594
00605 static titlelist *get_titlelist(int i) {
00606 titlelist *tl;
00607 int number;
00608
00609 if (i < 0 || i >= (int)arraysize(max_titles)) {
00610 LOG(llevInfo, "Warning: invalid book index %d, using 0 instead\n", i);
00611 return booklist;
00612 }
00613
00614 for (tl = booklist, number = i; tl && number; tl = tl->next, number--) {
00615 if (!tl->next)
00616 tl->next = get_empty_booklist();
00617 }
00618
00619 return tl;
00620 }
00621
00622
00623
00624
00636 static int nstrtok(const char *buf1, const char *buf2) {
00637 char *tbuf, buf[MAX_BUF];
00638 int number = 0;
00639
00640 if (!buf1 || !buf2)
00641 return 0;
00642
00643 snprintf(buf, sizeof(buf), "%s", buf1);
00644 for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
00645 number++;
00646 }
00647 return number;
00648 }
00649
00666 static char *strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size) {
00667 int maxi, i = nstrtok(buf1, buf2);
00668 char *tbuf, buf[MAX_BUF];
00669
00670 maxi = i;
00671 snprintf(buf, sizeof(buf), "%s", buf1);
00672 snprintf(retbuf, size, " ");
00673 for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
00674 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), "%s", tbuf);
00675 i--;
00676 if (i == 1 && maxi > 1)
00677 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), " and ");
00678 else if (i > 0 && maxi > 1)
00679 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ", ");
00680 else
00681 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf), ".");
00682 }
00683 return retbuf;
00684 }
00685
00696 int book_overflow(const char *buf1, const char *buf2, size_t booksize) {
00697 if (buf_overflow(buf1, buf2, BOOK_BUF-2)
00698 || buf_overflow(buf1, buf2, booksize))
00699 return 1;
00700 return 0;
00701 }
00702
00703
00704
00705
00706
00707
00708
00714 static void init_msgfile(void) {
00715 FILE *fp;
00716 char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp;
00717 int comp;
00718 static int did_init_msgfile = 0;
00719
00720 if (did_init_msgfile)
00721 return;
00722 did_init_msgfile = 1;
00723
00724 snprintf(fname, sizeof(fname), "%s/messages", settings.datadir);
00725 LOG(llevDebug, "Reading messages from %s...\n", fname);
00726
00727 fp = open_and_uncompress(fname, 0, &comp);
00728 if (fp != NULL) {
00729 linked_char *tmp = NULL;
00730 int lineno;
00731 int error_lineno;
00732
00733 error_lineno = 0;
00734 for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
00735 if (*buf == '#')
00736 continue;
00737 cp = strchr(buf, '\n');
00738 if (cp != NULL) {
00739 while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
00740 cp--;
00741 *cp = '\0';
00742 }
00743 if (tmp != NULL) {
00744 if (strcmp(buf, "ENDMSG") == 0) {
00745 if (strlen(msgbuf) > BOOK_BUF) {
00746 LOG(llevDebug, "Warning: this string exceeded max book buf size:\n");
00747 LOG(llevDebug, " %s\n", msgbuf);
00748 }
00749 tmp->name = add_string(msgbuf);
00750 tmp->next = first_msg;
00751 first_msg = tmp;
00752 nrofmsg++;
00753 tmp = NULL;
00754 } else if (!buf_overflow(msgbuf, buf, HUGE_BUF-1)) {
00755 strcat(msgbuf, buf);
00756 strcat(msgbuf, "\n");
00757 } else if (error_lineno != 0) {
00758 LOG(llevInfo, "Warning: truncating book at %s, line %d\n", fname, error_lineno);
00759 error_lineno = 0;
00760 }
00761 } else if (strcmp(buf, "MSG") == 0) {
00762 error_lineno = lineno;
00763 tmp = (linked_char *)malloc(sizeof(linked_char));
00764 strcpy(msgbuf, " ");
00765 } else {
00766 LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
00767 }
00768 }
00769 close_and_delete(fp, comp);
00770 }
00771
00772 #ifdef BOOK_MSG_DEBUG
00773 LOG(llevDebug, "init_info_listfile() got %d messages.\n", nrofmsg);
00774 #endif
00775 LOG(llevDebug, "done messages.\n");
00776 }
00777
00784 static void init_book_archive(void) {
00785 FILE *fp;
00786 int comp, nroftitle = 0;
00787 char buf[MAX_BUF], fname[MAX_BUF], *cp;
00788 static int did_init_barch = 0;
00789
00790 if (did_init_barch)
00791 return;
00792 did_init_barch = 1;
00793
00794 if (!booklist)
00795 booklist = get_empty_booklist();
00796
00797 snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
00798 LOG(llevDebug, " Reading bookarch from %s...\n", fname);
00799
00800 fp = open_and_uncompress(fname, 0, &comp);
00801 if (fp != NULL) {
00802 int type;
00803 size_t i;
00804 titlelist *bl;
00805 int lineno;
00806 title *book;
00807 int skipping;
00808
00809 skipping = 0;
00810 book = NULL;
00811 type = -1;
00812 for (lineno = 1; fgets(buf, MAX_BUF, fp) != NULL; lineno++) {
00813 int len;
00814 int value;
00815
00816 if (*buf == '#')
00817 continue;
00818 cp = strchr(buf, '\n');
00819 if (cp != NULL) {
00820 while (cp > buf && (cp[-1] == ' ' || cp[-1] == '\t'))
00821 cp--;
00822 *cp = '\0';
00823 }
00824 cp = buf;
00825 if (strncmp(buf, "title ", 6) == 0) {
00826 skipping = 0;
00827 cp = buf+6;
00828 while (*cp == ' ' || *cp == '\t')
00829 cp++;
00830 if (*cp == '\0') {
00831 LOG(llevInfo, "Warning: missing book title at %s, line %d\n", fname, lineno);
00832 book = NULL;
00833 } else {
00834 book = get_empty_book();
00835 book->name = add_string(cp);
00836 type = -1;
00837 nroftitle++;
00838 }
00839 } else if (book == NULL) {
00840 if (!skipping) {
00841 skipping = 1;
00842 LOG(llevInfo, "Warning: expecting 'title' at %s, line %d\n", fname, lineno);
00843 }
00844 } else if (strncmp(buf, "authour ", 8) == 0) {
00845 cp = buf+8;
00846 while (*cp == ' ' || *cp == '\t')
00847 cp++;
00848 if (*cp == '\0') {
00849 LOG(llevInfo, "Warning: missing book authour at %s, line %d\n", fname, lineno);
00850 } else {
00851 book->authour = add_string(cp);
00852 }
00853 } else if (strncmp(buf, "arch ", 5) == 0) {
00854 cp = buf+5;
00855 while (*cp == ' ' || *cp == '\t')
00856 cp++;
00857 if (*cp == '\0') {
00858 LOG(llevInfo, "Warning: missing book arch at %s, line %d\n", fname, lineno);
00859 } else {
00860 book->archname = add_string(cp);
00861 }
00862 } else if (sscanf(buf, "level %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
00863 book->level = value;
00864 } else if (sscanf(buf, "type %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
00865 type = value;
00866 } else if (sscanf(buf, "size %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
00867 book->size = value;
00868 } else if (sscanf(buf, "index %d%n", &value, &len) == 1 && len == (int)strlen(buf)) {
00869 book->msg_index = value;
00870 } else if (strcmp(buf, "end") == 0) {
00871 add_book(book, type, fname, lineno);
00872 book = NULL;
00873 type = -1;
00874 } else {
00875 LOG(llevInfo, "Warning: syntax error at %s, line %d\n", fname, lineno);
00876 }
00877 }
00878 if (book != NULL) {
00879 LOG(llevInfo, "Warning: missing 'end' at %s, line %d\n", fname, lineno);
00880 add_book(book, type, fname, lineno);
00881 }
00882 LOG(llevDebug, " book archives(used/avail):\n");
00883 for (bl = booklist, i = 0; bl != NULL && i < arraysize(max_titles); bl = bl->next, i++) {
00884 LOG(llevDebug, "(%d/%d)\n", bl->number, max_titles[i]);
00885 }
00886 close_and_delete(fp, comp);
00887 }
00888
00889 #ifdef BOOK_MSG_DEBUG
00890 LOG(llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle);
00891 #endif
00892 LOG(llevDebug, " done.\n");
00893 }
00894
00902 static void add_book(title *book, int type, const char *fname, int lineno) {
00903 titlelist *bl;
00904
00905 if (type == -1) {
00906 LOG(llevInfo, "Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
00907 type = 0;
00908 }
00909
00910 bl = get_titlelist(type);
00911 book->next = bl->first_book;
00912 bl->first_book = book;
00913 bl->number++;
00914 }
00915
00920 static void init_mon_info(void) {
00921 archetype *at;
00922 static int did_init_mon_info = 0;
00923
00924 if (did_init_mon_info)
00925 return;
00926 did_init_mon_info = 1;
00927
00928 for (at = first_archetype; at != NULL; at = at->next) {
00929 if (QUERY_FLAG(&at->clone, FLAG_MONSTER)
00930 && (!QUERY_FLAG(&at->clone, FLAG_CHANGING) || QUERY_FLAG(&at->clone, FLAG_UNAGGRESSIVE))) {
00931 objectlink *mon = (objectlink *)malloc(sizeof(objectlink));
00932 if (!mon) {
00933 LOG(llevError, "init_mon_info: malloc failed!\n");
00934 abort();
00935 }
00936 mon->ob = &at->clone;
00937 mon->id = nrofmon;
00938 mon->next = first_mon_info;
00939 first_mon_info = mon;
00940 nrofmon++;
00941 }
00942 }
00943 LOG(llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
00944 }
00945
00952 void init_readable(void) {
00953 static int did_this = 0;
00954
00955 if (did_this)
00956 return;
00957 did_this = 1;
00958
00959 LOG(llevDebug, "Initializing reading data...\n");
00960 init_msgfile();
00961 init_book_archive();
00962 init_mon_info();
00963 LOG(llevDebug, " done reading data\n");
00964 }
00965
00966
00967
00968
00969
00970
00971
00972
00984 static title *find_title(const object *book, int msgtype) {
00985 title *t;
00986 titlelist *tl;
00987 size_t length;
00988 int index;
00989
00990 if (msgtype < 0)
00991 return (title *)NULL;
00992
00993 tl = get_titlelist(msgtype);
00994 if (!tl)
00995 return (title *)NULL;
00996
00997 length = strlen(book->msg);
00998 index = strtoint(book->msg);
00999 for (t = tl->first_book; t; t = t->next)
01000 if (t->size == length && t->msg_index == index) {
01001 #ifdef ARCHIVE_DEBUG
01002 LOG(llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
01003 #endif
01004 return t;
01005 }
01006
01007 return (title *)NULL;
01008 }
01009
01023 static void new_text_name(object *book, int msgtype) {
01024 const char *name;
01025
01026 if (book->type != BOOK)
01027 return;
01028
01029 switch (msgtype) {
01030 case MSGTYPE_MONSTER:
01031 name = mon_book_name[RANDOM()%arraysize(mon_book_name)];
01032 break;
01033
01034 case MSGTYPE_ARTIFACT:
01035 name = art_book_name[RANDOM()%arraysize(art_book_name)];
01036 break;
01037
01038 case MSGTYPE_SPELLPATH:
01039 name = path_book_name[RANDOM()%arraysize(path_book_name)];
01040 break;
01041
01042 case MSGTYPE_ALCHEMY:
01043 name = formula_book_name[RANDOM()%arraysize(formula_book_name)];
01044 break;
01045
01046 case MSGTYPE_GODS:
01047 name = gods_book_name[RANDOM()%arraysize(gods_book_name)];
01048 break;
01049
01050 case MSGTYPE_MSGFILE:
01051 default:
01052 if (book->weight > 2000) {
01053 name = heavy_book_name[RANDOM()%arraysize(heavy_book_name)];
01054 } else {
01055 name = light_book_name[RANDOM()%arraysize(light_book_name)];
01056 }
01057 break;
01058 }
01059 free_string(book->name);
01060 book->name = add_string(name);
01061 }
01062
01072 static void add_author(object *op, int msgtype) {
01073 char title[MAX_BUF];
01074 const char *name;
01075
01076 if (msgtype < 0 || strlen(op->msg) < 5)
01077 return;
01078
01079 switch (msgtype) {
01080 case MSGTYPE_MONSTER:
01081 name = mon_author[RANDOM()%arraysize(mon_author)];
01082 break;
01083
01084 case MSGTYPE_ARTIFACT:
01085 name = art_author[RANDOM()%arraysize(art_author)];
01086 break;
01087
01088 case MSGTYPE_SPELLPATH:
01089 name = path_author[RANDOM()%arraysize(path_author)];
01090 break;
01091
01092 case MSGTYPE_ALCHEMY:
01093 name = formula_author[RANDOM()%arraysize(formula_author)];
01094 break;
01095
01096 case MSGTYPE_GODS:
01097 name = gods_author[RANDOM()%arraysize(gods_author)];
01098 break;
01099
01100 case MSGTYPE_MSGFILE:
01101 default:
01102 name = book_author[RANDOM()%arraysize(book_author)];
01103 }
01104
01105 snprintf(title, sizeof(title), "of %s", name);
01106 op->title = add_string(title);
01107 }
01108
01120 static int unique_book(const object *book, int msgtype) {
01121 title *test;
01122
01123 if (!booklist)
01124 return 1;
01125
01126
01127
01128
01129 for (test = get_titlelist(msgtype)->first_book; test; test = test->next) {
01130 if (!strcmp(test->name, book->name) && !strcmp(book->title, test->authour))
01131 return 0;
01132 }
01133 return 1;
01134 }
01135
01144 static void add_book_to_list(const object *book, int msgtype) {
01145 titlelist *tl = get_titlelist(msgtype);
01146 title *t;
01147
01148 if (!tl) {
01149 LOG(llevError, "add_book_to_list can't get booklist!\n");
01150 return;
01151 }
01152
01153 t = get_empty_book();
01154 t->name = add_string(book->name);
01155 t->authour = add_string(book->title);
01156 t->size = strlen(book->msg);
01157 t->msg_index = strtoint(book->msg);
01158 t->archname = add_string(book->arch->name);
01159 t->level = book->level;
01160
01161 t->next = tl->first_book;
01162 tl->first_book = t;
01163 tl->number++;
01164
01165
01166 need_to_write_bookarchive = 1;
01167
01168 #ifdef ARCHIVE_DEBUG
01169 LOG(llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
01170 #endif
01171 }
01172
01186 static void change_book(object *book, int msgtype) {
01187 titlelist *tl;
01188 title *t;
01189 int tries;
01190
01191 if (book->type != BOOK) {
01192 LOG(llevError, "change_book_name() called w/ illegal obj type.\n");
01193 return;
01194 }
01195
01196 tl = get_titlelist(msgtype);
01197 t = NULL;
01198 tries = 0;
01199
01200
01201
01202
01203
01204
01205
01206 if (strlen(book->msg) > 5 && (t = find_title(book, msgtype))) {
01207 object *tmpbook;
01208
01209
01210 tmpbook = create_archetype(t->archname);
01211 if (tmpbook->msg)
01212 free_string(tmpbook->msg);
01213 tmpbook->msg = add_string(book->msg);
01214 copy_object(tmpbook, book);
01215 free_object(tmpbook);
01216
01217 book->title = add_string(t->authour);
01218 free_string(book->name);
01219 book->name = add_string(t->name);
01220 book->level = t->level;
01221 } else {
01222 int numb, maxnames = max_titles[msgtype];
01223 const char *old_title;
01224 const char *old_name;
01225
01226 old_title = book->title ? add_string(book->title) : NULL;
01227 old_name = add_string(book->name);
01228
01229
01230
01231
01232
01233 if (!tl) {
01234 LOG(llevError, "change_book_name(): can't find title list\n");
01235 numb = 0;
01236 } else
01237 numb = tl->number;
01238
01239 if (numb == maxnames) {
01240 #ifdef ARCHIVE_DEBUG
01241 LOG(llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
01242 #endif
01243 if (old_title != NULL)
01244 free_string(old_title);
01245 free_string(old_name);
01246 return;
01247 }
01248
01249 if (!book->title)
01250 do {
01251
01252 new_text_name(book, msgtype);
01253 add_author(book, msgtype);
01254 tries++;
01255 } while (!unique_book(book, msgtype) && tries < MAX_TITLE_CHECK);
01256
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266 if (tries == MAX_TITLE_CHECK) {
01267 #ifdef ARCHIVE_DEBUG
01268 LOG(llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
01269 #endif
01270
01271 free_string(book->name);
01272 free_string(book->title);
01273 book->title = old_title != NULL ? add_string(old_title) : NULL;
01274
01275 if (RANDOM()%4) {
01276
01277 char new_name[MAX_BUF];
01278
01279 snprintf(new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM()%arraysize(book_descrpt)], old_name);
01280 book->name = add_string(new_name);
01281 } else {
01282 book->name = add_string(old_name);
01283 }
01284 } else if (book->title && strlen(book->msg) > 5) {
01285 add_book_to_list(book, msgtype);
01286 }
01287
01288 if (old_title != NULL)
01289 free_string(old_title);
01290 free_string(old_name);
01291 }
01292 }
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303
01304
01316 object *get_random_mon(int level) {
01317 objectlink *mon;
01318 int i, monnr;
01319
01320
01321 if (!nrofmon || !first_mon_info)
01322 return (object *)NULL;
01323
01324 if (!level) {
01325
01326 monnr = RANDOM()%nrofmon;
01327
01328 for (mon = first_mon_info, i = 0; mon; mon = mon->next, i++)
01329 if (i == monnr)
01330 break;
01331
01332 if (!mon) {
01333 LOG(llevError, "get_random_mon: Didn't find a monster when we should have\n");
01334 return NULL;
01335 }
01336 return mon->ob;
01337 }
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351
01352 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
01353 if (mon->ob->level >= level)
01354 i++;
01355
01356 if (i == 0) {
01357 LOG(llevError, "get_random_mon() couldn't return monster for level %d\n", level);
01358 return NULL;
01359 }
01360
01361 monnr = RANDOM()%i;
01362 for (mon = first_mon_info; mon; mon = mon->next)
01363 if (mon->ob->level >= level && monnr-- == 0)
01364 return mon->ob;
01365
01366 LOG(llevError, "get_random_mon(): didn't find a monster when we should have\n");
01367 return NULL;
01368 }
01369
01383 static char *mon_desc(const object *mon, char *buf, size_t size) {
01384 snprintf(buf, size, " *** %s ***\n", mon->name);
01385 describe_item(mon, NULL, buf+strlen(buf), size-strlen(buf));
01386 return buf;
01387 }
01388
01400 static object *get_next_mon(const object *tmp) {
01401 objectlink *mon;
01402
01403 for (mon = first_mon_info; mon; mon = mon->next)
01404 if (mon->ob == tmp)
01405 break;
01406
01407
01408 if (!mon)
01409 return NULL;
01410 if (mon->next)
01411 return mon->next->ob;
01412 else
01413 return first_mon_info->ob;
01414 }
01415
01429 static char *mon_info_msg(int level, char *buf, size_t booksize) {
01430 char tmpbuf[HUGE_BUF], desc[MAX_BUF];
01431 object *tmp;
01432
01433
01434 snprintf(buf, booksize, "This beastiary contains:");
01435
01436
01437
01438
01439
01440
01441
01442
01443 for (tmp = get_random_mon(level*3); tmp; tmp = get_next_mon(tmp)) {
01444
01445 snprintf(tmpbuf, sizeof(tmpbuf), "\n---\n%s", mon_desc(tmp, desc, sizeof(desc)));
01446
01447 if (book_overflow(buf, tmpbuf, booksize))
01448 break;
01449 snprintf(buf+strlen(buf), booksize-strlen(buf), "%s", tmpbuf);
01450 }
01451
01452 #ifdef BOOK_MSG_DEBUG
01453 LOG(llevDebug, "\n mon_info_msg() created strng: %d\n", strlen(retbuf));
01454 fprintf(logfile, " MADE THIS:\n%s\n", retbuf);
01455 #endif
01456
01457 return buf;
01458 }
01459
01460
01461
01462
01463
01477 static char *artifact_msg(int level, char *retbuf, size_t booksize) {
01478 artifactlist *al;
01479 artifact *art;
01480 int chance, i, type, index;
01481 int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
01482 char buf[BOOK_BUF], sbuf[MAX_BUF];
01483 object *tmp;
01484
01485
01486 if (book_entries > 5)
01487 book_entries = 5;
01488
01489
01490
01491
01492
01493
01494 i = 0;
01495 do {
01496 index = RANDOM()%arraysize(art_name_array);
01497 type = art_name_array[index].type;
01498 al = find_artifactlist(type);
01499 i++;
01500 } while (al == NULL && i < 10);
01501
01502 if (i == 10) {
01503 snprintf(retbuf, booksize, "None");
01504 return retbuf;
01505 }
01506
01507
01508
01509 art = al->items;
01510 for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
01511 if (art == NULL)
01512 art = al->items;
01513 art = art->next;
01514 }
01515
01516
01517 snprintf(retbuf, booksize, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
01518
01519
01520
01521
01522 while (book_entries > 0) {
01523 if (art == NULL)
01524 art = al->items;
01525
01526
01527 snprintf(buf, sizeof(buf), "---\n");
01528
01529
01530 if (art->allowed != NULL && strcmp(art->allowed->name, "All")) {
01531 linked_char *temp, *next = art->allowed;
01532
01533 do {
01534 temp = next;
01535 next = next->next;
01536 } while (next != (linked_char *)NULL && RANDOM()%2);
01537 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " A %s of %s", temp->name, art->item->name);
01538 } else {
01539
01540 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " The %s of %s", art_name_array[index].name, art->item->name);
01541 }
01542
01543
01544 chance = 100*((float)art->chance/al->total_chance);
01545 if (chance >= 20)
01546 snprintf(sbuf, sizeof(sbuf), "an uncommon");
01547 else if (chance >= 10)
01548 snprintf(sbuf, sizeof(sbuf), "an unusual");
01549 else if (chance >= 5)
01550 snprintf(sbuf, sizeof(sbuf), "a rare");
01551 else
01552 snprintf(sbuf, sizeof(sbuf), "a very rare");
01553 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " is %s\n", sbuf);
01554
01555
01556 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " item with a value that is %d times normal.\n",
01557 art->item->value);
01558
01559
01560
01561 if (art->item->msg && RANDOM()%4+1 < level
01562 && !(strlen(art->item->msg)+strlen(buf) > BOOK_BUF))
01563 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s", art->item->msg);
01564
01565
01566 tmp = get_object();
01567 add_abilities(tmp, art->item);
01568 tmp->type = type;
01569 SET_FLAG(tmp, FLAG_IDENTIFIED);
01570 describe_item(tmp, NULL, sbuf, sizeof(sbuf));
01571 if (strlen(sbuf) > 1)
01572 snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " Properties of this artifact include:\n %s\n", sbuf);
01573 free_object(tmp);
01574
01575 if (book_overflow(retbuf, buf, booksize))
01576 break;
01577 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "%s", buf);
01578
01579 art = art->next;
01580 book_entries--;
01581 }
01582
01583 #ifdef BOOK_MSG_DEBUG
01584 LOG(llevDebug, "artifact_msg() created strng: %d\n", strlen(retbuf));
01585 fprintf(logfile, " MADE THIS:\n%s", retbuf);
01586 #endif
01587 return retbuf;
01588 }
01589
01590
01591
01592
01593
01607 static char *spellpath_msg(int level, char *retbuf, size_t booksize) {
01608 int path = RANDOM()%NRSPELLPATHS, prayers = RANDOM()%2;
01609 int did_first_sp = 0;
01610 uint32 pnum = spellpathdef[path];
01611 archetype *at;
01612
01613
01614 snprintf(retbuf, booksize, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
01615
01616 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "belonging to the path of %s:\n", spellpathnames[path]);
01617
01618 for (at = first_archetype; at != NULL; at = at->next) {
01619
01620
01621
01622
01623 if (at->clone.type == SPELL
01624 && at->clone.path_attuned&pnum
01625 && ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers))
01626 && at->clone.level < level*8) {
01627 if (book_overflow(retbuf, at->clone.name, booksize))
01628 break;
01629
01630 if (did_first_sp)
01631 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), ",\n");
01632 did_first_sp = 1;
01633 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "%s", at->clone.name);
01634 }
01635 }
01636
01637 if (!did_first_sp) {
01638 if (RANDOM()%4)
01639 return spellpath_msg(level, retbuf, booksize);
01640
01641 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "\n - no known spells exist -\n");
01642 } else {
01643 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf), "\n");
01644 }
01645 return retbuf;
01646 }
01647
01656 static void make_formula_book(object *book, int level) {
01657 char retbuf[BOOK_BUF], title[MAX_BUF];
01658 recipelist *fl;
01659 recipe *formula;
01660 int chance;
01661 const char *op_name;
01662 archetype *at;
01663
01664
01665
01666
01667 fl = get_formulalist((RANDOM()%level)/3+1);
01668 if (!fl)
01669 fl = get_formulalist(1);
01670
01671 if (fl->total_chance == 0) {
01672 book->msg = add_string(" <indecipherable text>\n");
01673 new_text_name(book, MSGTYPE_ALCHEMY);
01674 add_author(book, MSGTYPE_ALCHEMY);
01675 return;
01676 }
01677
01678
01679 chance = RANDOM()%fl->total_chance;
01680 for (formula = fl->items; formula != NULL; formula = formula->next) {
01681 chance -= formula->chance;
01682 if (chance <= 0)
01683 break;
01684 }
01685
01686 if (!formula || formula->arch_names <= 0) {
01687 book->msg = add_string(" <indecipherable text>\n");
01688 new_text_name(book, MSGTYPE_ALCHEMY);
01689 add_author(book, MSGTYPE_ALCHEMY);
01690 return;
01691 }
01692
01693
01694
01695
01696
01697
01698 snprintf(retbuf, sizeof(retbuf), "Herein is described a project using %s:\n", formula->skill ? formula->skill : "an unknown skill");
01699
01700 op_name = formula->arch_name[RANDOM()%formula->arch_names];
01701 at = find_archetype(op_name);
01702 if (at == (archetype *)NULL) {
01703 LOG(llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
01704 book->msg = add_string(" <indecipherable text>\n");
01705 new_text_name(book, MSGTYPE_ALCHEMY);
01706 add_author(book, MSGTYPE_ALCHEMY);
01707 return;
01708 }
01709 op_name = at->clone.name;
01710
01711
01712 if (strcmp(formula->title, "NONE")) {
01713 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "The %s of %s", op_name, formula->title);
01714
01715
01716
01717
01718
01719 snprintf(title, sizeof(title), "%s: %s of %s", formula_book_name[RANDOM()%arraysize(formula_book_name)], op_name, formula->title);
01720 } else {
01721 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "The %s", op_name);
01722 snprintf(title, sizeof(title), "%s: %s", formula_book_name[RANDOM()%arraysize(formula_book_name)], op_name);
01723 if (at->clone.title) {
01724 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), " %s", at->clone.title);
01725 snprintf(title+strlen(title), sizeof(title)-strlen(title), " %s", at->clone.title);
01726 }
01727 }
01728
01729 if (book->name)
01730 free_string(book->name);
01731 book->name = add_string(title);
01732 if (book->title) {
01733 free_string(book->title);
01734 book->title = NULL;
01735 }
01736
01737
01738 if (formula->ingred != NULL) {
01739 linked_char *next;
01740 archetype *at;
01741 char name[MAX_BUF];
01742
01743 at = find_archetype(formula->cauldron);
01744 if (at)
01745 query_name(&at->clone, name, MAX_BUF);
01746 else
01747 snprintf(name, sizeof(name), "an unknown place");
01748
01749 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf),
01750 " may be made at %s using the following ingredients:\n", name);
01751
01752 for (next = formula->ingred; next != NULL; next = next->next) {
01753 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "%s\n", next->name);
01754 }
01755 } else
01756 LOG(llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, formula->title);
01757 if (retbuf[strlen(retbuf)-1] != '\n')
01758 snprintf(retbuf+strlen(retbuf), sizeof(retbuf)-strlen(retbuf), "\n");
01759 if (book->msg)
01760 free_string(book->msg);
01761 book->msg = add_string(retbuf);
01762 }
01763
01774 static char *msgfile_msg(int level, size_t booksize) {
01775 static char retbuf[BOOK_BUF];
01776 int i, msgnum;
01777 linked_char *msg = NULL;
01778
01779
01780 if (nrofmsg > 1) {
01781 msg = first_msg;
01782 msgnum = RANDOM()%nrofmsg;
01783 for (i = 0; msg && i < nrofmsg && i != msgnum; i++)
01784 msg = msg->next;
01785 }
01786
01787 if (msg && !book_overflow(retbuf, msg->name, booksize))
01788 snprintf(retbuf, sizeof(retbuf), "%s", msg->name);
01789 else
01790 snprintf(retbuf, sizeof(retbuf), "\n <undecipherable text>");
01791
01792 #ifdef BOOK_MSG_DEBUG
01793 LOG(llevDebug, "\n info_list_msg() created strng: %d\n", strlen(retbuf));
01794 LOG(llevDebug, " MADE THIS:\n%s\n", retbuf);
01795 #endif
01796
01797 return retbuf;
01798 }
01799
01813 static char *god_info_msg(int level, char *retbuf, size_t booksize) {
01814 const char *name;
01815 char buf[BOOK_BUF];
01816 int i;
01817 size_t retlen, buflen;
01818 size_t introlen;
01819 const object *god = pntr_to_god_obj(get_rand_god());
01820 char en[BOOK_BUF];
01821
01822 if (booksize > BOOK_BUF) {
01823 LOG(llevError, "common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (unsigned long)booksize, BOOK_BUF);
01824 booksize = BOOK_BUF;
01825 }
01826
01827 if (!god)
01828 return (char *)NULL;
01829 name = god->name;
01830
01831
01832 snprintf(retbuf, BOOK_BUF, "This document contains knowledge concerning the diety %s", name);
01833
01834 retlen = strlen(retbuf);
01835
01836
01837 if (nstrtok(god->msg, ",") > 0) {
01838 safe_strcat(retbuf, ", known as", &retlen, BOOK_BUF);
01839 safe_strcat(retbuf, strtoktolin(god->msg, ",", buf, sizeof(buf)), &retlen, BOOK_BUF);
01840 } else
01841 safe_strcat(retbuf, "...", &retlen, BOOK_BUF);
01842
01843 safe_strcat(retbuf, "\n ---\n", &retlen, BOOK_BUF);
01844
01845 introlen = retlen;
01846
01847
01848
01849
01850
01851
01852
01853 while (level > 0) {
01854 buf[0]=' ';
01855 buf[1]='\0';
01856 if (level == 2 && RANDOM()%2) {
01857
01858
01859 if (god->title)
01860 snprintf(buf, BOOK_BUF, "The gods %s and %s are enemies.\n ---\n", name, god->title);
01861 }
01862 if (level == 3 && RANDOM()%2) {
01863
01864 const char *enemy = god->slaying;
01865
01866 if (enemy && !(god->path_denied&PATH_TURNING)
01867 && (i = nstrtok(enemy, ",")) > 0) {
01868 char tmpbuf[MAX_BUF];
01869
01870 snprintf(buf, BOOK_BUF, "The holy words of %s have the power to slay creatures belonging to the ", name);
01871 if (i > 1)
01872 snprintf(tmpbuf, MAX_BUF, "following races:%s\n ---\n", strtoktolin(enemy, ",", en, sizeof(en)));
01873 else
01874 snprintf(tmpbuf, MAX_BUF, "race of%s\n ---\n", strtoktolin(enemy, ",", en, sizeof(en)));
01875
01876 buflen = strlen(buf);
01877 safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
01878 }
01879 }
01880 if (level == 4 && RANDOM()%2) {
01881
01882
01883 char cp[BOOK_BUF];
01884 describe_resistance(god, 1, cp, BOOK_BUF);
01885
01886 if (*cp) {
01887 snprintf(buf, BOOK_BUF, "%s has a potent aura which is extended to faithful priests. The effects of this aura include:\n%s\n ---\n", name, cp);
01888 }
01889 }
01890 if (level == 5 && RANDOM()%2) {
01891
01892 const char *race = god->race;
01893
01894 if (race && !(god->path_denied&PATH_SUMMON)) {
01895 i = nstrtok(race, ",");
01896 if (i > 0) {
01897 char tmpbuf[MAX_BUF];
01898
01899 snprintf(buf, BOOK_BUF, "Creatures sacred to %s include the\n", name);
01900
01901 if (i > 1)
01902 snprintf(tmpbuf, MAX_BUF, "following races:%s\n ---\n", strtoktolin(race, ",", en, sizeof(en)));
01903 else
01904 snprintf(tmpbuf, MAX_BUF, "race of %s\n ---\n", strtoktolin(race, ",", en, sizeof(en)));
01905
01906 buflen = strlen(buf);
01907 safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
01908 }
01909 }
01910 }
01911 if (level == 6 && RANDOM()%2) {
01912
01913
01914 char cp[MAX_BUF];
01915 describe_resistance(god, 1, cp, MAX_BUF);
01916
01917 if (*cp) {
01918 snprintf(buf, MAX_BUF, "\nThe priests of %s are known to be able to bestow a blessing which makes the recipient %s\n ---\n", name, cp);
01919 }
01920 }
01921 if (level == 8 && RANDOM()%2) {
01922
01923 int has_effect = 0, tmpvar;
01924 char tmpbuf[MAX_BUF];
01925
01926 snprintf(buf, MAX_BUF, "\nThe priests of %s are known to make cast a mighty prayer of possession which gives the recipient", name);
01927
01928 for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) {
01929 if (god->resist[tmpvar] == 100) {
01930 has_effect = 1;
01931 snprintf(tmpbuf, MAX_BUF, "Immunity to %s", attacktype_desc[tmpvar]);
01932 }
01933 }
01934 if (has_effect) {
01935 buflen = strlen(buf);
01936 safe_strcat(buf, tmpbuf, &buflen, BOOK_BUF);
01937 safe_strcat(buf, "\n ---\n", &buflen, BOOK_BUF);
01938 } else {
01939 buf[0]=' ';
01940 buf[1]='\0';
01941 }
01942 }
01943 if (level == 12 && RANDOM()%2) {
01944
01945 int has_effect = 0;
01946
01947 snprintf(buf, MAX_BUF, "It is rarely known fact that the priests of %s are mystically transformed. Effects of this include:\n", name);
01948 buflen = strlen(buf);
01949
01950 if (god->path_attuned) {
01951 has_effect = 1;
01952 DESCRIBE_PATH_SAFE(buf, god->path_attuned, "Attuned", &buflen, BOOK_BUF);
01953 }
01954 if (god->path_repelled) {
01955 has_effect = 1;
01956 DESCRIBE_PATH_SAFE(buf, god->path_repelled, "Repelled", &buflen, BOOK_BUF);
01957 }
01958 if (god->path_denied) {
01959 has_effect = 1;
01960 DESCRIBE_PATH_SAFE(buf, god->path_denied, "Denied", &buflen, BOOK_BUF);
01961 }
01962 if (has_effect) {
01963 safe_strcat(buf, "\n ---\n", &buflen, BOOK_BUF);
01964 } else {
01965 buf[0]=' ';
01966 buf[1]='\0';
01967 }
01968 }
01969
01970
01971
01972
01973
01974 if (book_overflow(retbuf, buf, booksize))
01975 break;
01976 if (strlen(buf) > 1)
01977 safe_strcat(retbuf, buf, &retlen, BOOK_BUF);
01978
01979 level--;
01980 }
01981 if (retlen == introlen) {
01982
01983 safe_strcat(retbuf, " Unfortunately the rest of the information is hopelessly garbled!\n ---\n", &retlen, BOOK_BUF);
01984 }
01985 #ifdef BOOK_MSG_DEBUG
01986 LOG(llevDebug, "\n god_info_msg() created strng: %d\n", strlen(retbuf));
01987 fprintf(logfile, " MADE THIS:\n%s", retbuf);
01988 #endif
01989 return retbuf;
01990 }
01991
02010 void tailor_readable_ob(object *book, int msg_type) {
02011 char msgbuf[BOOK_BUF];
02012 int level = book->level ? RANDOM()%book->level+1 : 1;
02013 size_t book_buf_size;
02014
02015
02016 if (book->type != BOOK)
02017 return;
02018
02019 if (level <= 0)
02020 return;
02021
02022
02023 book_buf_size = BOOKSIZE(book);
02024 book_buf_size -= strlen("\n");
02025
02026
02027
02028
02029
02030
02031
02032
02033
02034
02035
02036
02037
02038 msg_type = msg_type > 0 ? msg_type : RANDOM()%6;
02039 switch (msg_type) {
02040 case MSGTYPE_MONSTER:
02041 mon_info_msg(level, msgbuf, book_buf_size);
02042 break;
02043
02044 case MSGTYPE_ARTIFACT:
02045 artifact_msg(level, msgbuf, book_buf_size);
02046 break;
02047
02048 case MSGTYPE_SPELLPATH:
02049 spellpath_msg(level, msgbuf, book_buf_size);
02050 break;
02051
02052 case MSGTYPE_ALCHEMY:
02053 make_formula_book(book, level);
02054
02055 return;
02056 break;
02057
02058 case MSGTYPE_GODS:
02059 god_info_msg(level, msgbuf, book_buf_size);
02060 break;
02061
02062 case MSGTYPE_LIB:
02063 default:
02064 strcpy(msgbuf, msgfile_msg(level, book_buf_size));
02065 break;
02066 }
02067
02068 strcat(msgbuf, "\n");
02069 if (strlen(msgbuf) > strlen("\n")) {
02070 if (book->msg)
02071 free_string(book->msg);
02072 book->msg = add_string(msgbuf);
02073
02074 change_book(book, msg_type);
02075 }
02076 }
02077
02078
02079
02080
02081
02082
02083
02084 void free_all_readable(void) {
02085 titlelist *tlist, *tnext;
02086 title *title1, *titlenext;
02087 linked_char *lmsg, *nextmsg;
02088 objectlink *monlink, *nextmon;
02089
02090 LOG(llevDebug, "freeing all book information\n");
02091
02092 for (tlist = booklist; tlist != NULL; tlist = tnext) {
02093 tnext = tlist->next;
02094 for (title1 = tlist->first_book; title1; title1 = titlenext) {
02095 titlenext = title1->next;
02096 if (title1->name)
02097 free_string(title1->name);
02098 if (title1->authour)
02099 free_string(title1->authour);
02100 if (title1->archname)
02101 free_string(title1->archname);
02102 free(title1);
02103 }
02104 free(tlist);
02105 }
02106 for (lmsg = first_msg; lmsg; lmsg = nextmsg) {
02107 nextmsg = lmsg->next;
02108 if (lmsg->name)
02109 free_string(lmsg->name);
02110 free(lmsg);
02111 }
02112 for (monlink = first_mon_info; monlink; monlink = nextmon) {
02113 nextmon = monlink->next;
02114 free(monlink);
02115 }
02116 }
02117
02118
02119
02120
02121
02122
02123
02127 void write_book_archive(void) {
02128 FILE *fp;
02129 int index;
02130 char fname[MAX_BUF];
02131 title *book;
02132 titlelist *bl;
02133
02134
02135 if (!need_to_write_bookarchive)
02136 return;
02137
02138 snprintf(fname, sizeof(fname), "%s/bookarch", settings.localdir);
02139 LOG(llevDebug, "Updating book archive: %s...\n", fname);
02140
02141 fp = fopen(fname, "w");
02142 if (fp == NULL) {
02143 LOG(llevDebug, "Can't open book archive file %s\n", fname);
02144 return;
02145 }
02146
02147 for (bl = get_titlelist(0), index = 0; bl; bl = bl->next, index++) {
02148 for (book = bl->first_book; book; book = book->next)
02149 if (book && book->authour) {
02150 fprintf(fp, "title %s\n", book->name);
02151 fprintf(fp, "authour %s\n", book->authour);
02152 fprintf(fp, "arch %s\n", book->archname);
02153 fprintf(fp, "level %d\n", book->level);
02154 fprintf(fp, "type %d\n", index);
02155
02156 fprintf(fp, "size %lu\n", (unsigned long)book->size);
02157 fprintf(fp, "index %d\n", book->msg_index);
02158 fprintf(fp, "end\n");
02159 }
02160 }
02161 if (ferror(fp)) {
02162 LOG(llevError, "Error during book archive save.\n");
02163 fclose(fp);
02164 return;
02165 }
02166 if (fclose(fp) != 0) {
02167 LOG(llevError, "Error during book archive save.\n");
02168 return;
02169 }
02170 chmod(fname, SAVE_MODE);
02171 need_to_write_bookarchive = 0;
02172 }
02173
02181 const readable_message_type *get_readable_message_type(object *readable) {
02182 uint8 subtype = readable->subtype;
02183
02184 if (subtype > last_readable_subtype)
02185 return &readable_message_types[0];
02186 return &readable_message_types[subtype];
02187 }