ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/readable.C
Revision: 1.24
Committed: Thu May 24 03:33:28 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_1
Changes since 1.23: +21 -135 lines
Log Message:
add books from books.pod via some most dire hacks

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
23 */
24
25
26 /* This file contains code relevant to the BOOKS hack -- designed
27 * to allow randomly occuring messages in non-magical texts.
28 */
29
30 /* laid down initial file - dec 1995. -b.t. thomas@astro.psu.edu */
31
32 #include <global.h>
33 #include <book.h>
34 #include <living.h>
35 #include <spells.h>
36
37
38 /* Define this if you want to archive book titles by contents.
39 * This option should enforce UNIQUE combinations of titles,authors and
40 * msg contents during and *between* game sessions.
41 * Note: a slight degeneracy exists since books are archived based on an integer
42 * index value calculated from the message text (similar to alchemy formulae).
43 * Sometimes two widely different messages have the same index value (rare). In
44 * this case, it is possible to occasionally generate 2 books with same title and
45 * different message content. Not really a bug, but rather a feature. This action
46 * should keeps player on their toes ;).
47 * Also, note that there is *finite* space available for archiving message and titles.
48 * Once this space is used, books will stop being archived. Not a serious problem
49 * under the current regime, since there are generally fewer possible (random)
50 * messages than space available on the titlelists.
51 * One exception (for sure) are the monster messages. But no worries, you should
52 * see all of the monster info in some order (but not all possble combinations)
53 * before the monster titlelist space is run out. You can increase titlelist
54 * space by increasing the array sizes for the monster book_authours and book_names
55 * (see max_titles[] array and include/read.h). Since the unique_book algorthm is
56 * kinda stupid, this program *may* slow down program execution if defined (but I don't
57 * think its a significant problem, at least, I have no problems running this option
58 * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg
59 * combinations have been generated, unique_book isnt called anymore. It takes 5-10
60 * sessions for this to happen).
61 * Final note: the game remembers book/title/msg combinations from reading the
62 * file lib/bookarch. If you REMOVE this file, you will lose your archive. So
63 * be sure to copy it over to the new lib directory when you change versions.
64 * -b.t.
65 */
66
67 /* This flag is useful to see what kind of output messages are created */
68
69 /* #define BOOK_MSG_DEBUG */
70
71 /* This flag is useful for debuging archiving action */
72
73 /* #define ARCHIVE_DEBUG */
74
75 /* Moved these structures from struct.h to this file in 0.94.3 - they
76 * are not needed anyplace else, so why have them globally declared?
77 */
78
79 /* 'title' and 'titlelist' are used by the readable code */
80 struct title : zero_initialised
81 {
82 shstr name; /* the name of the book */
83 shstr authour; /* the name of the book authour */
84 shstr archname; /* the archetype name of the book */
85 int level; /* level of difficulty of this message */
86 int size; /* size of the book message */
87 int msg_index; /* an index value derived from book message */
88 title *next;
89 };
90
91 struct titlelist : zero_initialised
92 {
93 int number; /* number of items in the list */
94 title *first_book; /* pointer to first book in this list */
95 titlelist *next; /* pointer to next book list */
96 };
97
98 /* special structure, used only by art_name_array[] */
99 struct arttypename
100 {
101 const char *name; /* generic name to call artifacts of this type */
102 int type; /* matching type */
103 };
104
105 /* booklist is the buffer of books read in from the bookarch file */
106 static titlelist *booklist = NULL;
107
108 static objectlink *first_mon_info = NULL;
109
110 /* these are needed for creation of a linked list of
111 * pointers to all (hostile) monster objects */
112
113 static int nrofmon = 0, need_to_write_bookarchive = 0;
114
115
116 /* this is needed to keep track of status of initialisation
117 * of the message file */
118 static int nrofmsg = 0;
119
120 /* first_msg is the started of the linked list of messages as read from
121 * the messages file
122 */
123 static linked_char *first_msg = NULL;
124
125 /*
126 * Spellpath information
127 */
128
129 static uint32 spellpathdef[NRSPELLPATHS] = {
130 PATH_PROT,
131 PATH_FIRE,
132 PATH_FROST,
133 PATH_ELEC,
134 PATH_MISSILE,
135 PATH_SELF,
136 PATH_SUMMON,
137 PATH_ABJURE,
138 PATH_RESTORE,
139 PATH_DETONATE,
140 PATH_MIND,
141 PATH_CREATE,
142 PATH_TELE,
143 PATH_INFO,
144 PATH_TRANSMUTE,
145 PATH_TRANSFER,
146 PATH_TURNING,
147 PATH_WOUNDING,
148 PATH_DEATH,
149 PATH_LIGHT
150 };
151
152 static const char *const path_book_name[] = {
153 "codex",
154 "compendium",
155 "exposition",
156 "tables",
157 "treatise"
158 };
159
160 /* used by spellpath texts */
161 static const char *const path_author[] = {
162 "aether",
163 "astral byways",
164 "connections",
165 "the Grey Council",
166 "deep pathways",
167 "knowledge",
168 "magic",
169 "mystic ways",
170 "pathways",
171 "power",
172 "spells",
173 "transforms",
174 "the mystic veil",
175 "unknown spells"
176 };
177
178 /*
179 * Artiface/item information
180 */
181
182 /* if it isnt listed here, then art_attr_msg will never generate
183 * a message for this type of artifact. -b.t. */
184
185 static arttypename art_name_array[] = {
186 {"Helmet", HELMET},
187 {"Amulet", AMULET},
188 {"Shield", SHIELD},
189 {"Bracers", BRACERS},
190 {"Boots", BOOTS},
191 {"Cloak", CLOAK},
192 {"Gloves", GLOVES},
193 {"Girdle", GIRDLE},
194 {"Ring", RING},
195 {"Horn", HORN},
196 {"Missile Weapon", BOW},
197 {"Missile", ARROW},
198 {"Hand Weapon", WEAPON},
199 {"Artifact", SKILL},
200 {"Food", FOOD},
201 {"Body Armour", ARMOUR}
202 };
203
204 static const char *const art_book_name[] = {
205 "collection",
206 "file",
207 "files",
208 "guide",
209 "handbook",
210 "index",
211 "inventory",
212 "list",
213 "listing",
214 "record",
215 "record book"
216 };
217
218 /* used by artifact texts */
219 static const char *const art_author[] = {
220 "ancient things",
221 "artifacts",
222 "Havlor", /* ancient warrior scribe :) */
223 "items",
224 "lost artifacts",
225 "the ancients",
226 "useful things"
227 };
228
229 /*
230 * Monster book information
231 */
232
233 static const char *const mon_book_name[] = {
234 "beastuary",
235 "catalog",
236 "compilation",
237 "collection",
238 "encyclopedia",
239 "guide",
240 "handbook",
241 "list",
242 "manual",
243 "notes",
244 "record",
245 "register",
246 "volume"
247 };
248
249
250 /* used by monster beastuary texts */
251 static const char *const mon_author[] = {
252 "beasts",
253 "creatures",
254 "dezidens",
255 "dwellers",
256 "evil nature",
257 "life",
258 "monsters",
259 "nature",
260 "new life",
261 "residents",
262 "the spawn",
263 "the living",
264 "things"
265 };
266
267 /*
268 * God book information
269 */
270
271 static const char *const gods_book_name[] = {
272 "devotional",
273 "devout notes",
274 "divine text",
275 "divine work",
276 "holy book",
277 "holy record",
278 "moral text",
279 "sacred guide",
280 "testament",
281 "transcript"
282 };
283
284 /* used by gods texts */
285 static const char *const gods_author[] = {
286 "cults",
287 "joy",
288 "lasting curse",
289 "madness",
290 "religions",
291 "the dead",
292 "the gods",
293 "the heirophant",
294 "the poor priest",
295 "the priestess",
296 "pain",
297 "white"
298 };
299
300
301 /*
302 * Alchemy (formula) information
303 */
304
305 static const char *const formula_book_name[] = {
306 "cookbook",
307 "formulary",
308 "lab book",
309 "lab notes",
310 "recipe book",
311 "experiment record",
312 "work plan",
313 "design notes"
314 };
315
316 /* this isn't used except for empty books */
317 static const char *const formula_author[] = {
318 "Albertus Magnus",
319 "alchemy",
320 "balms",
321 "creation",
322 "dusts",
323 "magical manufacture",
324 "making",
325 "philosophical items",
326 "potions",
327 "powders",
328 "the cauldron",
329 "the lamp black",
330 "transmutation",
331 "waters"
332 };
333
334 /*
335 * Generic book information
336 */
337
338 /* used by msg file and 'generic' books */
339 static const char *const light_book_name[] = {
340 "calendar",
341 "datebook",
342 "diary",
343 "guidebook",
344 "handbook",
345 "ledger",
346 "notes",
347 "notebook",
348 "octavo",
349 "pamphlet",
350 "practicum",
351 "script",
352 "transcript"
353 };
354
355 static const char *const heavy_book_name[] = {
356 "catalog",
357 "compendium",
358 "guide",
359 "manual",
360 "opus",
361 "tome",
362 "treatise",
363 "volume",
364 "work"
365 };
366
367
368 /* used by 'generic' books */
369 static const char *const book_author[] = {
370 "Abdulah",
371 "Al'hezred",
372 "Alywn",
373 "Arundel",
374 "Arvind",
375 "Aerlingas",
376 "Bacon",
377 "Baliqendii",
378 "Bosworth",
379 "Beathis",
380 "Bertil",
381 "Cauchy",
382 "Chakrabarti",
383 "der Waalis",
384 "Dirk",
385 "Djwimii",
386 "Eisenstaadt",
387 "Fendris",
388 "Frank",
389 "Habbi",
390 "Harlod",
391 "Ichibod",
392 "Janus",
393 "June",
394 "Magnuson",
395 "Nandii",
396 "Nitfeder",
397 "Norris",
398 "Parael",
399 "Penhew",
400 "Sophia",
401 "Skilly",
402 "Tahir",
403 "Thockmorton",
404 "Thomas",
405 "van Helsing",
406 "van Pelt",
407 "Voormis",
408 "Xavier",
409 "Xeno",
410 "Zardoz",
411 "Zagy"
412 };
413
414 static const char *const book_descrpt[] = {
415 "ancient",
416 "cryptic",
417 "cryptical",
418 "dusty",
419 "hiearchical",
420 "grizzled",
421 "gold-guilt",
422 "great",
423 "lost",
424 "magnificent",
425 "musty",
426 "mythical",
427 "mystical",
428 "rustic",
429 "stained",
430 "silvered",
431 "transcendental",
432 "weathered"
433 };
434
435 /* Each line of this array is a readable subtype
436 * Be careful to keep the order. If you add readable subtype, add them
437 * at the bottom of the list. Never delete a subtype because index is used as
438 * subtype paramater in arch files!
439 */
440 static readable_message_type readable_message_types[] = {
441 /*subtype 0 */ {0, 0},
442 /* book messages subtypes */
443 /*subtype 1 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1},
444 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_2},
445 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_1},
446 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_2},
447 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_1},
448 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_2},
449 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_EVOKER},
450 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PRAYER},
451 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PYRO},
452 /*subtype 10 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER},
453 {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SUMMONER},
454 /* card messages subtypes */
455 {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_1},
456 {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_2},
457 {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_3},
458 {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_1},
459 {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_2},
460 {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_3},
461 {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_1},
462 {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_2},
463 /*subtype 20 */ {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3},
464 {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_1},
465 {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_2},
466 {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_3},
467
468 /* Paper messages subtypes */
469 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_1},
470 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_2},
471 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_3},
472 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_1},
473 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_2},
474 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_1},
475 /*subtype 30 */ {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2},
476 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_1},
477 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_2},
478 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_1},
479 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_2},
480 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_1},
481 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_2},
482 {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_MAGIC},
483
484 /* road signs messages subtypes */
485 {MSG_TYPE_SIGN, MSG_TYPE_SIGN_BASIC},
486 {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_LEFT},
487 /*subtype 40 */ {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT},
488 {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_BOTH},
489
490 /* stones and monument messages */
491 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_1},
492 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_2},
493 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_3},
494 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_1},
495 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_2},
496 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_3},
497 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_1},
498 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_2},
499 /*subtype 50 */ {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_3},
500 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_1},
501 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_2},
502 {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_3}
503 };
504 int last_readable_subtype = sizeof (readable_message_types) / sizeof (readable_message_type);
505
506 static int max_titles[6] = {
507 ((sizeof (light_book_name) / sizeof (char *)) + (sizeof (heavy_book_name) / sizeof (char *))) * (sizeof (book_author) / sizeof (char *)),
508 (sizeof (mon_book_name) / sizeof (char *)) * (sizeof (mon_author) / sizeof (char *)),
509 (sizeof (art_book_name) / sizeof (char *)) * (sizeof (art_author) / sizeof (char *)),
510 (sizeof (path_book_name) / sizeof (char *)) * (sizeof (path_author) / sizeof (char *)),
511 (sizeof (formula_book_name) / sizeof (char *)) * (sizeof (formula_author) / sizeof (char *)),
512 (sizeof (gods_book_name) / sizeof (char *)) * (sizeof (gods_author) / sizeof (char *))
513 };
514
515 /******************************************************************************
516 *
517 * Start of misc. readable functions used by others functions in this file
518 *
519 *****************************************************************************/
520
521 static titlelist *
522 get_empty_booklist (void)
523 {
524 titlelist *bl = new titlelist;
525
526 bl->number = 0;
527 bl->first_book = NULL;
528 bl->next = NULL;
529 return bl;
530 }
531
532 static title *
533 get_empty_book (void)
534 {
535 title *t = new title;
536
537 t->name = NULL;
538 t->archname = NULL;
539 t->authour = NULL;
540 t->level = 0;
541 t->size = 0;
542 t->msg_index = 0;
543 t->next = NULL;
544 return t;
545 }
546
547 /* get_titlelist() - returns pointer to the title list referanced by i */
548
549 static titlelist *
550 get_titlelist (int i)
551 {
552 titlelist *tl = booklist;
553 int number = i;
554
555 if (number < 0)
556 return tl;
557
558 while (tl && number)
559 {
560 if (!tl->next)
561 tl->next = get_empty_booklist ();
562
563 tl = tl->next;
564 number--;
565 }
566
567 return tl;
568 }
569
570 /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file
571 * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */
572
573 /* nstrtok() - simple routine to return the number of list
574 * items in buf1 as separated by the value of buf2
575 */
576
577 int
578 nstrtok (const char *buf1, const char *buf2)
579 {
580 char *tbuf, sbuf[12], buf[MAX_BUF];
581 int number = 0;
582
583 if (!buf1 || !buf2)
584 return 0;
585 sprintf (buf, "%s", buf1);
586 sprintf (sbuf, "%s", buf2);
587 tbuf = strtok (buf, sbuf);
588 while (tbuf)
589 {
590 number++;
591 tbuf = strtok (NULL, sbuf);
592 }
593 return number;
594 }
595
596 /* strtoktolin() - takes a string in buf1 and separates it into
597 * a list of strings delimited by buf2. Then returns a comma
598 * separated string w/ decent punctuation.
599 */
600
601 char *
602 strtoktolin (const char *buf1, const char *buf2)
603 {
604 int maxi, i = nstrtok (buf1, buf2);
605 char *tbuf, buf[MAX_BUF], sbuf[12];
606 static char rbuf[BOOK_BUF];
607
608 maxi = i;
609 strcpy (buf, buf1);
610 strcpy (sbuf, buf2);
611 strcpy (rbuf, " ");
612 tbuf = strtok (buf, sbuf);
613 while (tbuf && i > 0)
614 {
615 strcat (rbuf, tbuf);
616 i--;
617 if (i == 1 && maxi > 1)
618 strcat (rbuf, " and ");
619 else if (i > 0 && maxi > 1)
620 strcat (rbuf, ", ");
621 else
622 strcat (rbuf, ".");
623 tbuf = strtok (NULL, sbuf);
624 }
625 return (char *) rbuf;
626 }
627
628 int
629 book_overflow (const char *buf1, const char *buf2, int booksize)
630 {
631
632 if (buf_overflow (buf1, buf2, BOOK_BUF - 2) /* 2 less so always room for trailing \n */
633 || buf_overflow (buf1, buf2, booksize))
634 return 1;
635 return 0;
636
637
638 }
639
640 /*****************************************************************************
641 *
642 * Start of initialisation related functions.
643 *
644 ****************************************************************************/
645
646 /* init_book_archive() - if not called before, initialise the info list
647 * This reads in the bookarch file into memory. bookarch is the file
648 * created and updated across multiple runs of the program.
649 */
650 static void
651 init_book_archive (void)
652 {
653 FILE *fp;
654 int comp, nroftitle = 0;
655 char buf[MAX_BUF], fname[MAX_BUF], *cp;
656 title *book = NULL;
657 titlelist *bl = get_empty_booklist ();
658 static int did_init_barch;
659
660 if (did_init_barch)
661 return;
662
663 did_init_barch = 1;
664
665 if (!booklist)
666 booklist = bl;
667
668 sprintf (fname, "%s/bookarch", settings.localdir);
669 LOG (llevDebug, " Reading bookarch from %s...\n", fname);
670
671 if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL)
672 {
673 int value, type = 0;
674 size_t i;
675
676 while (fgets (buf, MAX_BUF, fp) != NULL)
677 {
678 if (*buf == '#')
679 continue;
680 if ((cp = strchr (buf, '\n')) != NULL)
681 *cp = '\0';
682 cp = buf;
683 while (*cp == ' ') /* Skip blanks */
684 cp++;
685 if (!strncmp (cp, "title", 4))
686 {
687 book = get_empty_book (); /* init new book entry */
688 book->name = strchr (cp, ' ') + 1;
689 type = -1;
690 nroftitle++;
691 continue;
692 }
693 if (!strncmp (cp, "authour", 4))
694 {
695 book->authour = strchr (cp, ' ') + 1;
696 }
697 if (!strncmp (cp, "arch", 4))
698 {
699 book->archname = strchr (cp, ' ') + 1;
700 }
701 else if (sscanf (cp, "level %d", &value))
702 {
703 book->level = (uint16) value;
704 }
705 else if (sscanf (cp, "type %d", &value))
706 {
707 type = (uint16) value;
708 }
709 else if (sscanf (cp, "size %d", &value))
710 {
711 book->size = (uint16) value;
712 }
713 else if (sscanf (cp, "index %d", &value))
714 {
715 book->msg_index = (uint16) value;
716 }
717 else if (!strncmp (cp, "end", 3))
718 { /* link it */
719 bl = get_titlelist (type);
720 book->next = bl->first_book;
721 bl->first_book = book;
722 bl->number++;
723 }
724 }
725 LOG (llevDebug, "book archives(used/avail): \n");
726 for (bl = booklist, i = 0; bl != NULL && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++)
727 {
728 LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]);
729 }
730 close_and_delete (fp, comp);
731 }
732
733 #ifdef BOOK_MSG_DEBUG
734 LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle);
735 #endif
736 LOG (llevDebug, " done.\n");
737 }
738
739 /* init_mon_info() - creates the linked list of pointers to
740 * monster archetype objects if not called previously
741 */
742
743 static void
744 init_mon_info (void)
745 {
746 archetype *at;
747 static int did_init_mon_info = 0;
748
749 if (did_init_mon_info)
750 return;
751
752 did_init_mon_info = 1;
753
754
755 for (at = first_archetype; at != NULL; at = at->next)
756 {
757 if (QUERY_FLAG (&at->clone, FLAG_MONSTER) && (!QUERY_FLAG (&at->clone, FLAG_CHANGING) || QUERY_FLAG (&at->clone, FLAG_UNAGGRESSIVE)))
758 {
759 objectlink *mon = new objectlink;
760
761 mon->ob = &at->clone;
762 mon->next = first_mon_info;
763 first_mon_info = mon;
764 nrofmon++;
765 }
766 }
767
768 LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
769 }
770
771 /* init_readable() - initialise linked lists utilized by
772 * message functions in tailor_readable_ob()
773 *
774 * This is the function called by the main routine to initialise
775 * all the readable information.
776 */
777 void
778 init_readable (void)
779 {
780 static int did_this;
781
782 if (did_this)
783 return;
784
785 did_this = 1;
786
787 LOG (llevDebug, "Initialising reading data...\n");
788 init_book_archive ();
789 init_mon_info ();
790 LOG (llevDebug, " Done\n");
791 }
792
793 /*****************************************************************************
794 *
795 * This is the start of the administrative functions when creating
796 * new books (ie, updating title and the like)
797 *
798 *****************************************************************************/
799
800 /* find_title() - Search the titlelist (based on msgtype) to see if
801 * book matches something already there. IF so, return that title.
802 */
803 static title *
804 find_title (const object *book, int msgtype)
805 {
806 title *t = NULL;
807 titlelist *tl = get_titlelist (msgtype);
808 int length = strlen (book->msg);
809 int index = strtoint (book->msg);
810
811 if (msgtype < 0)
812 return (title *) NULL;
813
814 if (tl)
815 t = tl->first_book;
816
817 while (t)
818 if (t->size == length && t->msg_index == index)
819 break;
820 else
821 t = t->next;
822
823 #ifdef ARCHIVE_DEBUG
824 if (t)
825 LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
826 #endif
827
828 return t;
829 }
830
831 /* new_text_name() - Only for objects of type BOOK. SPELLBOOK stuff is
832 * handled directly in change_book_name(). Names are based on text
833 * msgtype
834 * this sets book book->name based on msgtype given. What name
835 * is given is based on various criteria
836 */
837
838 static void
839 new_text_name (object *book, int msgtype)
840 {
841 int nbr;
842 char name[MAX_BUF];
843
844 if (book->type != BOOK)
845 return;
846
847 switch (msgtype)
848 {
849 case 1: /*monster */
850 nbr = sizeof (mon_book_name) / sizeof (char *);
851 assign (name, mon_book_name[rndm (nbr)]);
852 break;
853 case 2: /*artifact */
854 nbr = sizeof (art_book_name) / sizeof (char *);
855 assign (name, art_book_name[rndm (nbr)]);
856 break;
857 case 3: /*spellpath */
858 nbr = sizeof (path_book_name) / sizeof (char *);
859 assign (name, path_book_name[rndm (nbr)]);
860 break;
861 case 4: /*alchemy */
862 nbr = sizeof (formula_book_name) / sizeof (char *);
863 assign (name, formula_book_name[rndm (nbr)]);
864 break;
865 case 5: /*gods */
866 nbr = sizeof (gods_book_name) / sizeof (char *);
867 assign (name, gods_book_name[rndm (nbr)]);
868 break;
869 case 6: /*msg file */
870 default:
871 if (book->weight > 2000)
872 { /* based on weight */
873 nbr = sizeof (heavy_book_name) / sizeof (char *);
874 assign (name, heavy_book_name[rndm (nbr)]);
875 }
876 else if (book->weight < 2001)
877 {
878 nbr = sizeof (light_book_name) / sizeof (char *);
879 assign (name, light_book_name[rndm (nbr)]);
880 }
881 break;
882 }
883
884 book->name = name;
885 }
886
887 /* add_book_author()
888 * A lot like new_text_name above, but instead chooses an author
889 * and sets op->title to that value
890 */
891
892 static void
893 add_author (object *op, int msgtype)
894 {
895 char title[MAX_BUF], name[MAX_BUF];
896 int nbr = sizeof (book_author) / sizeof (char *);
897
898 if (msgtype < 0 || strlen (op->msg) < 5)
899 return;
900
901 switch (msgtype)
902 {
903 case 1: /* monster */
904 nbr = sizeof (mon_author) / sizeof (char *);
905 assign (name, mon_author[rndm (nbr)]);
906 break;
907 case 2: /* artifacts */
908 nbr = sizeof (art_author) / sizeof (char *);
909 assign (name, art_author[rndm (nbr)]);
910 break;
911 case 3: /* spellpath */
912 nbr = sizeof (path_author) / sizeof (char *);
913 assign (name, path_author[rndm (nbr)]);
914 break;
915 case 4: /* alchemy */
916 nbr = sizeof (formula_author) / sizeof (char *);
917 assign (name, formula_author[rndm (nbr)]);
918 break;
919 case 5: /* gods */
920 nbr = sizeof (gods_author) / sizeof (char *);
921 assign (name, gods_author[rndm (nbr)]);
922 break;
923 case 6: /* msg file */
924 default:
925 assign (name, book_author[rndm (nbr)]);
926 }
927
928 sprintf (title, "of %s", name);
929 op->title = title;
930 }
931
932 /* unique_book() - check to see if the book title/msg is unique. We
933 * go through the entire list of possibilities each time. If we find
934 * a match, then unique_book returns true (because inst unique).
935 */
936
937 static int
938 unique_book (const object *book, int msgtype)
939 {
940 title *test;
941
942 if (!booklist)
943 return 1; /* No archival entries! Must be unique! */
944
945 /* Go through the booklist. If the author and name match, not unique so
946 * return 0.
947 */
948 for (test = get_titlelist (msgtype)->first_book; test; test = test->next)
949 {
950 if (!strcmp (test->name, book->name) && !strcmp (book->title, test->authour))
951 return 0;
952 }
953 return 1;
954 }
955
956 /* add_book_to_list() */
957
958 static void
959 add_book_to_list (const object *book, int msgtype)
960 {
961 titlelist *tl = get_titlelist (msgtype);
962 title *t;
963
964 if (!tl)
965 {
966 LOG (llevError, "add_book_to_list can't get booklist!\n");
967 return;
968 }
969
970 t = get_empty_book ();
971 t->name = book->name;
972 t->authour = book->title;
973 t->size = strlen (book->msg);
974 t->msg_index = strtoint (book->msg);
975 t->archname = book->arch->name;
976 t->level = book->level;
977
978 t->next = tl->first_book;
979 tl->first_book = t;
980 tl->number++;
981
982 /* We have stuff we need to write now */
983 need_to_write_bookarchive = 1;
984
985 #ifdef ARCHIVE_DEBUG
986 LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
987 #endif
988
989 }
990
991
992 /* change_book() - give a new, fancier name to generated
993 * objects of type BOOK and SPELLBOOK.
994 * Aug 96 I changed this so we will attempt to create consistent
995 * authour/title and message content for BOOKs. Also, we will
996 * alter books that match archive entries to the archival
997 * levels and architypes. -b.t.
998 */
999
1000 #define MAX_TITLE_CHECK 20
1001
1002 void
1003 change_book (object *book, int msgtype)
1004 {
1005 int nbr = sizeof (book_descrpt) / sizeof (char *);
1006
1007 switch (book->type)
1008 {
1009 case BOOK:
1010 {
1011 titlelist *tl = get_titlelist (msgtype);
1012 title *t = NULL;
1013 int tries = 0;
1014
1015 /* look to see if our msg already been archived. If so, alter
1016 * the book to match the archival text. If we fail to match,
1017 * then we archive the new title/name/msg combo if there is
1018 * room on the titlelist.
1019 */
1020
1021 if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype)))
1022 {
1023 object *tmpbook;
1024
1025 /* alter book properties */
1026 if ((tmpbook = get_archetype (t->archname)) != NULL)
1027 {
1028 tmpbook->msg = book->msg;
1029 tmpbook->copy_to (book);
1030 tmpbook->destroy ();
1031 }
1032
1033 book->title = t->authour;
1034 book->name = t->name;
1035 book->level = t->level;
1036 }
1037 /* Don't have any default title, so lets make up a new one */
1038 else
1039 {
1040 int numb, maxnames = max_titles[msgtype];
1041 const char *old_title;
1042 const char *old_name;
1043
1044 old_title = book->title;
1045 old_name = book->name;
1046
1047 /* some pre-generated books have title already set (from
1048 * maps), also don't bother looking for unique title if
1049 * we already used up all the available names! */
1050
1051 if (!tl)
1052 {
1053 LOG (llevError, "change_book_name(): can't find title list\n");
1054 numb = 0;
1055 }
1056 else
1057 numb = tl->number;
1058
1059 if (numb == maxnames)
1060 {
1061 #ifdef ARCHIVE_DEBUG
1062 LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1063 #endif
1064 break;
1065 }
1066 /* shouldnt change map-maker books */
1067 else if (!book->title)
1068 do
1069 {
1070 /* random book name */
1071 new_text_name (book, msgtype);
1072 add_author (book, msgtype); /* random author */
1073 tries++;
1074 }
1075 while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK);
1076
1077 /* Now deal with 2 cases.
1078 * 1)If no space for a new title exists lets just restore
1079 * the old book properties. Remember, if the book had
1080 * matchd an older entry on the titlelist, we shouldnt
1081 * have called this routine in the first place!
1082 * 2) If we got a unique title, we need to add it to
1083 * the list.
1084 */
1085
1086 if (tries == MAX_TITLE_CHECK || numb == maxnames)
1087 { /* got to check maxnames again */
1088 #ifdef ARCHIVE_DEBUG
1089 LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1090 #endif
1091 /* restore old book properties here */
1092 book->title = old_title;
1093
1094 if (RANDOM () % 4)
1095 {
1096 /* Lets give the book a description to individualize it some */
1097 char new_name[MAX_BUF];
1098
1099 snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[rndm (nbr)], old_name);
1100
1101 book->name = new_name;
1102 }
1103 else
1104 {
1105 book->name = old_name;
1106 }
1107 }
1108 else if (book->title && strlen (book->msg) > 5)
1109 { /* archive if long msg texts */
1110 add_book_to_list (book, msgtype);
1111 }
1112 }
1113 break;
1114 }
1115
1116 default:
1117 LOG (llevError, "change_book_name() called w/ illegal obj type.\n");
1118 return;
1119 }
1120 }
1121
1122 /*****************************************************************************
1123 *
1124 * This is the start of the area that generates the actual contents
1125 * of the book.
1126 *
1127 *****************************************************************************/
1128
1129 /*****************************************************************************
1130 * Monster msg generation code.
1131 ****************************************************************************/
1132
1133 /* get_random_mon() - returns a random monster slected from linked
1134 * list of all monsters in the current game. If level is non-zero,
1135 * then only monsters greater than that level will be returned.
1136 * Changed 971225 to be greater than equal to level passed. Also
1137 * made choosing by level more random.
1138 */
1139
1140 object *
1141 get_random_mon (int level)
1142 {
1143 objectlink *mon = first_mon_info;
1144 int i = 0, monnr;
1145
1146 /* safety check. Problem w/ init_mon_info list? */
1147 if (!nrofmon || !mon)
1148 return (object *) NULL;
1149
1150 if (!level)
1151 {
1152 /* lets get a random monster from the mon_info linked list */
1153 monnr = RANDOM () % nrofmon;
1154
1155 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1156 if (i++ == monnr)
1157 break;
1158
1159 if (!mon)
1160 {
1161 LOG (llevError, "get_random_mon: Didn't find a monster when we should have\n");
1162 return NULL;
1163 }
1164 return mon->ob;
1165 }
1166
1167 /* Case where we are searching by level. Redone 971225 to be clearer
1168 * and more random. Before, it looks like it took a random monster from
1169 * the list, and then returned the first monster after that which was
1170 * appropriate level. This wasn't very random because if you had a
1171 * bunch of low level monsters and then a high level one, if the random
1172 * determine took one of the low level ones, it would just forward to the
1173 * high level one and return that. Thus, monsters that immediatly followed
1174 * a bunch of low level monsters would be more heavily returned. It also
1175 * means some of the dragons would be poorly represented, since they
1176 * are a group of high level monsters all around each other.
1177 */
1178
1179 /* First count number of monsters meeting level criteria */
1180 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1181 if (mon->ob->level >= level)
1182 i++;
1183
1184 if (i == 0)
1185 {
1186 LOG (llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1187 return NULL;
1188 }
1189
1190 monnr = RANDOM () % i;
1191 for (mon = first_mon_info; mon; mon = mon->next)
1192 if (mon->ob->level >= level && monnr-- == 0)
1193 return mon->ob;
1194
1195 if (!mon)
1196 {
1197 LOG (llevError, "get_random_mon(): didn't find a monster when we should have\n");
1198 return NULL;
1199 }
1200 return NULL; /* Should be unreached, by keeps warnings down */
1201 }
1202
1203 /*
1204 * Returns a description of the monster. This really needs to be
1205 * redone, as describe_item really gives a pretty internal description.
1206 */
1207
1208 char *
1209 mon_desc (const object *mon)
1210 {
1211 static char retbuf[HUGE_BUF];
1212
1213 sprintf (retbuf, " *** %s ***\n", &mon->name);
1214 strcat (retbuf, describe_item (mon, NULL));
1215
1216 return retbuf;
1217 }
1218
1219
1220 /* This function returns the next monsters after 'tmp'. If no match is
1221 * found, it returns NULL (changed 0.94.3 to do this, since the
1222 * calling function (mon_info_msg) seems to expect that.
1223 */
1224
1225 object *
1226 get_next_mon (object *tmp)
1227 {
1228 objectlink *mon;
1229
1230 for (mon = first_mon_info; mon; mon = mon->next)
1231 if (mon->ob == tmp)
1232 break;
1233
1234 /* didn't find a match */
1235 if (!mon)
1236 return NULL;
1237 if (mon->next)
1238 return mon->next->ob;
1239 else
1240 return first_mon_info->ob;
1241
1242 }
1243
1244
1245
1246 /* mon_info_msg() - generate a message detailing the properties
1247 * of a randomly selected monster.
1248 */
1249
1250 char *
1251 mon_info_msg (int level, int booksize)
1252 {
1253 static char retbuf[BOOK_BUF];
1254 char tmpbuf[HUGE_BUF];
1255 object *tmp;
1256
1257 /*preamble */
1258 strcpy (retbuf, "This beastiary contains:");
1259
1260 /* lets print info on as many monsters as will fit in our
1261 * document.
1262 * 8-96 Had to change this a bit, otherwise there would
1263 * have been an impossibly large number of combinations
1264 * of text! (and flood out the available number of titles
1265 * in the archive in a snap!) -b.t.
1266 */
1267 tmp = get_random_mon (level * 3);
1268 while (tmp)
1269 {
1270 /* monster description */
1271 sprintf (tmpbuf, "\n---\n%s", mon_desc (tmp));
1272
1273 if (!book_overflow (retbuf, tmpbuf, booksize))
1274 strcat (retbuf, tmpbuf);
1275 else
1276 break;
1277
1278 /* Note that the value this returns is not based on level */
1279 tmp = get_next_mon (tmp);
1280 }
1281
1282 #ifdef BOOK_MSG_DEBUG
1283 LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf));
1284 fprintf (logfile, " MADE THIS:\n%s\n", retbuf);
1285 #endif
1286
1287 return retbuf;
1288 }
1289
1290
1291 /*****************************************************************************
1292 * Artifact msg generation code.
1293 ****************************************************************************/
1294
1295 /* artifact_msg() - generate a message detailing the properties
1296 * of 1-6 artifacts drawn sequentially from the artifact list.
1297 */
1298 const char *
1299 artifact_msg (int level, int booksize)
1300 {
1301 artifactlist *al = NULL;
1302 artifact *art;
1303 int chance, i, type, index;
1304 int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1;
1305 const char *ch;
1306 char name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF];
1307 static char retbuf[BOOK_BUF];
1308 object *tmp = NULL;
1309
1310 /* values greater than 5 create msg buffers that are too big! */
1311 if (book_entries > 5)
1312 book_entries = 5;
1313
1314 /* lets determine what kind of artifact type randomly.
1315 * Right now legal artifacts only come from those listed
1316 * in art_name_array. Also, we check to be sure an artifactlist
1317 * for that type exists!
1318 */
1319 i = 0;
1320 do
1321 {
1322 index = RANDOM () % (sizeof (art_name_array) / sizeof (arttypename));
1323 type = art_name_array[index].type;
1324 al = find_artifactlist (type);
1325 i++;
1326 }
1327 while ((al == NULL) && (i < 10));
1328
1329 if (i == 10) /* Unable to find a message */
1330 return "None";
1331
1332 /* There is no reason to start on the artifact list at the begining. Lets
1333 * take our starting position randomly... */
1334 art = al->items;
1335 for (i = RANDOM () % level + RANDOM () % 2 + 1; i > 0; i--)
1336 {
1337 if (art == NULL)
1338 art = al->items; /* hmm, out of stuff, loop back around */
1339 art = art->next;
1340 }
1341
1342 /* the base 'generic' name for our artifact */
1343 assign (name, art_name_array[index].name);
1344
1345 /* Ok, lets print out the contents */
1346 sprintf (retbuf, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1347
1348 /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1349 * as long as we have space up to the allowed max # (book_entires)
1350 */
1351 while (book_entries > 0)
1352 {
1353
1354 if (art == NULL)
1355 art = al->items;
1356
1357 /* separator of items */
1358 strcpy (buf, "--- \n");
1359
1360 /* Name */
1361 if (art->allowed != NULL && strcmp (art->allowed->name, "All"))
1362 {
1363 linked_char *temp, *next = art->allowed;
1364
1365 do
1366 {
1367 temp = next;
1368 next = next->next;
1369 }
1370 while (next && !RANDOM () % 2);
1371 sprintf (buf, "%s A %s of %s", buf, &temp->name, &art->item->name);
1372 }
1373 else /* default name is used */
1374 sprintf (buf, "%s The %s of %s", buf, name, &art->item->name);
1375
1376 /* chance of finding */
1377 chance = (int) (100 * ((float) art->chance / al->total_chance));
1378 if (chance >= 20)
1379 sprintf (sbuf, "an uncommon");
1380 else if (chance >= 10)
1381 sprintf (sbuf, "an unusual");
1382 else if (chance >= 5)
1383 sprintf (sbuf, "a rare");
1384 else
1385 sprintf (sbuf, "a very rare");
1386 sprintf (buf, "%s is %s\n", buf, sbuf);
1387
1388 /* value of artifact */
1389 sprintf (buf, "%s item with a value that is %d times normal.\n", buf, art->item->value);
1390
1391 /* include the message about the artifact, if exists, and book
1392 * level is kinda high */
1393 if (art->item->msg && (RANDOM () % 4 + 1) < level && !((strlen (art->item->msg) + strlen (buf)) > BOOK_BUF))
1394 strcat (buf, art->item->msg);
1395
1396 /* properties of the artifact */
1397 tmp = object::create ();
1398 add_abilities (tmp, art->item);
1399 tmp->type = type;
1400 SET_FLAG (tmp, FLAG_IDENTIFIED);
1401 if ((ch = describe_item (tmp, NULL)) != NULL && strlen (ch) > 1)
1402 sprintf (buf, "%s Properties of this artifact include: \n %s \n", buf, ch);
1403 tmp->destroy ();
1404 /* add the buf if it will fit */
1405 if (!book_overflow (retbuf, buf, booksize))
1406 strcat (retbuf, buf);
1407 else
1408 break;
1409
1410 art = art->next;
1411 book_entries--;
1412 }
1413
1414 #ifdef BOOK_MSG_DEBUG
1415 LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf));
1416 fprintf (logfile, " MADE THIS:\n%s", retbuf);
1417 #endif
1418 return retbuf;
1419 }
1420
1421 /*****************************************************************************
1422 * Spellpath message generation
1423 *****************************************************************************/
1424
1425 /* spellpath_msg() - generate a message detailing the member
1426 * incantations/prayers (and some of their properties) belonging to
1427 * a given spellpath.
1428 */
1429
1430 char *
1431 spellpath_msg (int level, int booksize)
1432 {
1433 static char retbuf[BOOK_BUF];
1434 char tmpbuf[BOOK_BUF];
1435 int path = RANDOM () % NRSPELLPATHS, prayers = RANDOM () % 2;
1436 int did_first_sp = 0;
1437 uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path];
1438 archetype *at;
1439
1440 /* Preamble */
1441 sprintf (retbuf, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
1442
1443 if (path == -1)
1444 strcat (retbuf, "having no known spell path.\n");
1445 else
1446 sprintf (retbuf, "%sbelonging to the path of %s:\n", retbuf, spellpathnames[path]);
1447
1448 for (at = first_archetype; at != NULL; at = at->next)
1449 {
1450 /* Determine if this is an appropriate spell. Must
1451 * be of matching path, must be of appropriate type (prayer
1452 * or not), and must be within the valid level range.
1453 */
1454 if (at->clone.type == SPELL && at->clone.path_attuned & pnum &&
1455 ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers)) && (at->clone.level < (level * 8)))
1456 {
1457 assign (tmpbuf, at->clone.name);
1458
1459 if (book_overflow (retbuf, tmpbuf, booksize))
1460 break;
1461 else
1462 {
1463 if (did_first_sp)
1464 strcat (retbuf, ",\n");
1465 did_first_sp = 1;
1466 strcat (retbuf, tmpbuf);
1467 }
1468 }
1469 }
1470 /* Geez, no spells were generated. */
1471 if (!did_first_sp)
1472 {
1473 if (RANDOM () % 4) /* usually, lets make a recursive call... */
1474 spellpath_msg (level, booksize);
1475 else /* give up, cause knowing no spells exist for path is info too. */
1476 strcat (retbuf, "\n - no known spells exist -\n");
1477 }
1478 else
1479 {
1480 strcat (retbuf, "\n");
1481 }
1482 return retbuf;
1483 }
1484
1485 /* formula_msg() - generate a message detailing the properties
1486 * of a randomly selected alchemical formula.
1487 */
1488 void
1489 make_formula_book (object *book, int level)
1490 {
1491 char retbuf[BOOK_BUF], title[MAX_BUF];
1492 recipelist *fl;
1493 recipe *formula = NULL;
1494 int chance;
1495
1496 /* the higher the book level, the more complex (ie number of
1497 * ingredients) the formula can be.
1498 */
1499 fl = get_formulalist (((RANDOM () % level) / 3) + 1);
1500
1501 if (!fl)
1502 fl = get_formulalist (1); /* safety */
1503
1504 if (fl->total_chance == 0)
1505 {
1506 book->msg = "<indecipherable text>\n";
1507 new_text_name (book, 4);
1508 add_author (book, 4);
1509 return;
1510 }
1511
1512 /* get a random formula, weighted by its bookchance */
1513 chance = RANDOM () % fl->total_chance;
1514 for (formula = fl->items; formula != NULL; formula = formula->next)
1515 {
1516 chance -= formula->chance;
1517 if (chance <= 0)
1518 break;
1519 }
1520
1521 if (!formula || formula->arch_names <= 0)
1522 {
1523 book->msg = "<indecipherable text>\n";
1524 new_text_name (book, 4);
1525 add_author (book, 4);
1526
1527 }
1528 else
1529 {
1530 /* looks like a formula was found. Base the amount
1531 * of information on the booklevel and the spellevel
1532 * of the formula. */
1533
1534 const char *op_name = formula->arch_name[RANDOM () % formula->arch_names];
1535 archetype *at;
1536
1537 /* preamble */
1538 sprintf (retbuf, "Herein is described a project using %s: \n", formula->skill ? &formula->skill : "an unknown skill");
1539
1540 if ((at = archetype::find (op_name)) != (archetype *) NULL)
1541 op_name = at->clone.name;
1542 else
1543 LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1544
1545 /* item name */
1546 if (strcmp (formula->title, "NONE"))
1547 {
1548 sprintf (retbuf, "%sThe %s of %s", retbuf, op_name, &formula->title);
1549 /* This results in things like pile of philo. sulfur.
1550 * while philo. sulfur may look better, without this,
1551 * you get things like 'the wise' because its missing the
1552 * water of section.
1553 */
1554 sprintf (title, "%s: %s of %s",
1555 formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title);
1556 }
1557 else
1558 {
1559 sprintf (retbuf, "%sThe %s", retbuf, op_name);
1560 sprintf (title, "%s: %s", formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name);
1561 if (at->clone.title)
1562 {
1563 strcat (retbuf, " ");
1564 strcat (retbuf, at->clone.title);
1565 strcat (title, " ");
1566 strcat (title, at->clone.title);
1567 }
1568 }
1569 /* Lets name the book something meaningful ! */
1570 book->name = title;
1571 book->title = NULL;
1572
1573 /* ingredients to make it */
1574 if (formula->ingred != NULL)
1575 {
1576 linked_char *next;
1577 archetype *at;
1578
1579 at = archetype::find (formula->cauldron);
1580
1581 sprintf (retbuf + strlen (retbuf),
1582 " may be made at %s using the following ingredients:\n", at ? query_name (&at->clone) : "an unknown place");
1583
1584 for (next = formula->ingred; next != NULL; next = next->next)
1585 {
1586 strcat (retbuf, next->name);
1587 strcat (retbuf, "\n");
1588 }
1589 }
1590 else
1591 LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title);
1592 if (retbuf[strlen (retbuf) - 1] != '\n')
1593 strcat (retbuf, "\n");
1594
1595 book->msg = retbuf;
1596 }
1597 }
1598
1599 /* god_info_msg() - generate a message detailing the properties
1600 * of a random god. Used by the book hack. b.t.
1601 */
1602 const char *
1603 god_info_msg (int level, int booksize)
1604 {
1605 static char retbuf[BOOK_BUF];
1606 const char *name = NULL;
1607 char buf[BOOK_BUF];
1608 int i;
1609 size_t introlen;
1610 object *god = pntr_to_god_obj (get_rand_god ());
1611
1612 if (!god)
1613 return (char *) NULL; /* oops, problems... */
1614 name = god->name;
1615
1616 /* preamble.. */
1617 sprintf (retbuf, "This document contains knowledge concerning\n");
1618 sprintf (retbuf, "%sthe diety %s", retbuf, name);
1619
1620 /* Always have as default information the god's descriptive terms. */
1621 if (nstrtok (god->msg, ",") > 0)
1622 {
1623 strcat (retbuf, ", known as");
1624 strcat (retbuf, strtoktolin (god->msg, ","));
1625 }
1626 else
1627 strcat (retbuf, "...");
1628
1629 strcat (retbuf, "\n ---\n");
1630 introlen = strlen (retbuf); /* so we will know if no new info is added later */
1631
1632 /* Information about the god is random, and based on the level of the
1633 * 'book'. Probably there is a more intellegent way to implement
1634 * this ...
1635 */
1636
1637 while (level > 0)
1638 {
1639 sprintf (buf, " ");
1640 if (level == 2 && RANDOM () % 2)
1641 { /* enemy god */
1642 const char *enemy = god->title;
1643
1644 if (enemy)
1645 sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy);
1646 }
1647
1648 if (level == 3 && RANDOM () % 2)
1649 { /* enemy race, what the god's holy word effects */
1650 const char *enemy = god->slaying;
1651
1652 if (enemy && !(god->path_denied & PATH_TURNING))
1653 if ((i = nstrtok (enemy, ",")) > 0)
1654 {
1655 char tmpbuf[MAX_BUF];
1656
1657 sprintf (buf, "The holy words of %s have the power to\n", name);
1658 strcat (buf, "slay creatures belonging to the ");
1659 if (i > 1)
1660 sprintf (tmpbuf, "following \n races:%s", strtoktolin (enemy, ","));
1661 else
1662 sprintf (tmpbuf, "race of%s", strtoktolin (enemy, ","));
1663 sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1664 }
1665 }
1666
1667 if (level == 4 && RANDOM () % 2)
1668 { /* Priest of god gets these protect,vulnerable... */
1669 char tmpbuf[MAX_BUF];
1670
1671 if (const char *cp = describe_resistance (god, 1))
1672 { /* This god does have protections */
1673 sprintf (tmpbuf, "%s has a potent aura which is extended\n", name);
1674 strcat (tmpbuf, "faithful priests. The effects of this aura include:\n");
1675 strcat (tmpbuf, cp);
1676 strcat (buf, tmpbuf);
1677 strcat (buf, "\n ---\n");
1678 }
1679 else
1680 sprintf (buf, " ");
1681 }
1682
1683 if (level == 5 && RANDOM () % 2)
1684 { /* aligned race, summoning */
1685 const char *race = god->race; /* aligned race */
1686
1687 if (race && !(god->path_denied & PATH_SUMMON))
1688 if ((i = nstrtok (race, ",")) > 0)
1689 {
1690 char tmpbuf[MAX_BUF];
1691
1692 sprintf (buf, "Creatures sacred to %s include the \n", name);
1693 if (i > 1)
1694 sprintf (tmpbuf, "following \n races:%s", strtoktolin (race, ","));
1695 else
1696 sprintf (tmpbuf, "race of%s", strtoktolin (race, ","));
1697 sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1698 }
1699 }
1700
1701 if (level == 6 && RANDOM () % 2)
1702 { /* blessing,curse properties of the god */
1703 char tmpbuf[MAX_BUF];
1704
1705 if (const char *cp = describe_resistance (god, 1))
1706 { /* This god does have protections */
1707 sprintf (tmpbuf, "\nThe priests of %s are known to be able to \n", name);
1708 strcat (tmpbuf, "bestow a blessing which makes the recipient\n");
1709 strcat (tmpbuf, cp);
1710 strcat (buf, tmpbuf);
1711 strcat (buf, "\n ---\n");
1712 }
1713 else
1714 sprintf (buf, " ");
1715
1716 }
1717
1718 if (level == 8 && RANDOM () % 2)
1719 { /* immunity, holy possession */
1720 int has_effect = 0, tmpvar;
1721 char tmpbuf[MAX_BUF];
1722
1723 sprintf (tmpbuf, "\n");
1724 sprintf (tmpbuf, "The priests of %s are known to make cast a mighty \n", name);
1725
1726 strcat (tmpbuf, "prayer of possession which gives the recipient\n");
1727
1728 for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
1729 {
1730 if (god->resist[tmpvar] == 100)
1731 {
1732 has_effect = 1;
1733 sprintf (tmpbuf + strlen (tmpbuf), "Immunity to %s", attacktype_desc[tmpvar]);
1734 }
1735 }
1736
1737 if (has_effect)
1738 {
1739 strcat (buf, tmpbuf);
1740 strcat (buf, "\n ---\n");
1741 }
1742 else
1743 sprintf (buf, " ");
1744 }
1745
1746 if (level == 12 && RANDOM () % 2)
1747 { /* spell paths */
1748 int has_effect = 0, tmpvar;
1749 char tmpbuf[MAX_BUF];
1750
1751 sprintf (tmpbuf, "\n");
1752 sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name);
1753 strcat (tmpbuf, "are mystically transformed. Effects of this include:\n");
1754
1755 if ((tmpvar = god->path_attuned))
1756 {
1757 has_effect = 1;
1758 DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned");
1759 }
1760
1761 if ((tmpvar = god->path_repelled))
1762 {
1763 has_effect = 1;
1764 DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled");
1765 }
1766
1767 if ((tmpvar = god->path_denied))
1768 {
1769 has_effect = 1;
1770 DESCRIBE_PATH (tmpbuf, tmpvar, "Denied");
1771 }
1772
1773 if (has_effect)
1774 {
1775 strcat (buf, tmpbuf);
1776 strcat (buf, "\n ---\n");
1777 }
1778 else
1779 sprintf (buf, " ");
1780 }
1781
1782 /* check to be sure new buffer size dont exceed either
1783 * the maximum buffer size, or the 'natural' size of the
1784 * book...
1785 */
1786 if (book_overflow (retbuf, buf, booksize))
1787 break;
1788 else if (strlen (buf) > 1)
1789 strcat (retbuf, buf);
1790
1791 level--;
1792 }
1793
1794 if (strlen (retbuf) == introlen)
1795 { /* we got no information beyond the preamble! */
1796 strcat (retbuf, " [Unfortunately the rest of the information is\n");
1797 strcat (retbuf, " hopelessly garbled!]\n ---\n");
1798 }
1799 #ifdef BOOK_MSG_DEBUG
1800 LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf));
1801 fprintf (logfile, " MADE THIS:\n%s", retbuf);
1802 #endif
1803 return retbuf;
1804 }
1805
1806 /* tailor_readable_ob()- The main routine. This chooses a random
1807 * message to put in given readable object (type==BOOK) which will
1808 * be referred hereafter as a 'book'. We use the book level to de-
1809 * termine the value of the information we will insert. Higher
1810 * values mean the book will (generally) have better/more info.
1811 * See individual cases as to how this will be utilized.
1812 * "Book" name/content length are based on the weight of the
1813 * document. If the value of msg_type is negative, we will randomly
1814 * choose the kind of message to generate.
1815 * -b.t. thomas@astro.psu.edu
1816 *
1817 * book is the object we are creating into.
1818 * If msg_type is a positive value, we use that to determine the
1819 * message type - otherwise a random value is used.
1820 *
1821 */
1822 void
1823 tailor_readable_ob (object *book, int msg_type)
1824 {
1825 char msgbuf[BOOK_BUF];
1826 int level = book->level ? (RANDOM () % book->level) + 1 : 1;
1827 int book_buf_size;
1828
1829 /* safety */
1830 if (book->type != BOOK)
1831 return;
1832
1833 if (level <= 0)
1834 return; /* if no level no point in doing any more... */
1835
1836 /* Max text length this book can have. */
1837 book_buf_size = BOOKSIZE (book);
1838
1839 /* &&& The message switch &&& */
1840 /* Below all of the possible types of messages in the "book"s.
1841 */
1842 /*
1843 * IF you add a new type of book msg, you will have to do several things.
1844 * 1) make sure there is an entry in the msg switch below!
1845 * 2) make sure there is an entry in max_titles[] array.
1846 * 3) make sure there are entries for your case in new_text_title()
1847 * and add_authour().
1848 * 4) you may want separate authour/book name arrays in read.h
1849 */
1850
1851 msg_type = msg_type > 0 ? msg_type : (RANDOM () % 6);
1852 switch (msg_type)
1853 {
1854 case 1: /* monster attrib */
1855 strcpy (msgbuf, mon_info_msg (level, book_buf_size));
1856 break;
1857 case 2: /* artifact attrib */
1858 strcpy (msgbuf, artifact_msg (level, book_buf_size));
1859 break;
1860 case 3: /* grouping incantations/prayers by path */
1861 strcpy (msgbuf, spellpath_msg (level, book_buf_size));
1862 break;
1863 case 4: /* describe an alchemy formula */
1864 make_formula_book (book, level);
1865 /* make_formula_book already gives title */
1866 return;
1867 break;
1868 case 5: /* bits of information about a god */
1869 strcpy (msgbuf, god_info_msg (level, book_buf_size));
1870 break;
1871 case 0: /* use info list in lib/ */
1872 default:
1873 cfperl_make_book (book, level);
1874 return;
1875 }
1876
1877 strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
1878
1879 if (strlen (msgbuf) > 1)
1880 {
1881 book->msg = msgbuf;
1882 /* lets give the "book" a new name, which may be a compound word */
1883 change_book (book, msg_type);
1884 }
1885
1886 }
1887
1888
1889 /*****************************************************************************
1890 *
1891 * Cleanup routine for readble stuff.
1892 *
1893 *****************************************************************************/
1894
1895 void
1896 free_all_readable (void)
1897 {
1898 titlelist *tlist, *tnext;
1899 title *title1, *titlenext;
1900 linked_char *lmsg, *nextmsg;
1901 objectlink *monlink, *nextmon;
1902
1903 LOG (llevDebug, "freeing all book information\n");
1904
1905 for (tlist = booklist; tlist != NULL; tlist = tnext)
1906 {
1907 tnext = tlist->next;
1908
1909 for (title1 = tlist->first_book; title1; title1 = titlenext)
1910 {
1911 titlenext = title1->next;
1912 delete title1;
1913 }
1914
1915 delete tlist;
1916 }
1917
1918 for (lmsg = first_msg; lmsg; lmsg = nextmsg)
1919 {
1920 nextmsg = lmsg->next;
1921 delete lmsg;
1922 }
1923
1924 for (monlink = first_mon_info; monlink; monlink = nextmon)
1925 {
1926 nextmon = monlink->next;
1927 delete monlink;
1928 }
1929 }
1930
1931
1932 /*****************************************************************************
1933 *
1934 * Writeback routine for updating the bookarchive.
1935 *
1936 ****************************************************************************/
1937
1938 /* write_book_archive() - write out the updated book archive */
1939
1940 void
1941 write_book_archive (void)
1942 {
1943 FILE *fp;
1944 int index = 0;
1945 char fname[MAX_BUF];
1946 title *book = NULL;
1947 titlelist *bl = get_titlelist (0);
1948
1949 /* If nothing changed, don't write anything */
1950 if (!need_to_write_bookarchive)
1951 return;
1952 need_to_write_bookarchive = 0;
1953
1954 sprintf (fname, "%s/bookarch", settings.localdir);
1955 LOG (llevDebug, "Updating book archive: %s...\n", fname);
1956
1957 if ((fp = fopen (fname, "w")) == NULL)
1958 {
1959 LOG (llevDebug, "Can't open book archive file %s\n", fname);
1960 }
1961 else
1962 {
1963 while (bl)
1964 {
1965 for (book = bl->first_book; book; book = book->next)
1966 if (book && book->authour)
1967 {
1968 fprintf (fp, "title %s\n", &book->name);
1969 fprintf (fp, "authour %s\n", &book->authour);
1970 fprintf (fp, "arch %s\n", &book->archname);
1971 fprintf (fp, "level %d\n", book->level);
1972 fprintf (fp, "type %d\n", index);
1973 fprintf (fp, "size %d\n", book->size);
1974 fprintf (fp, "index %d\n", book->msg_index);
1975 fprintf (fp, "end\n");
1976 }
1977 bl = bl->next;
1978 index++;
1979 }
1980 fclose (fp);
1981 chmod (fname, SAVE_MODE);
1982 }
1983 }
1984 readable_message_type *
1985 get_readable_message_type (object *readable)
1986 {
1987 uint8 subtype = readable->subtype;
1988
1989 if (subtype > last_readable_subtype)
1990 return &(readable_message_types[0]);
1991 return &(readable_message_types[subtype]);
1992 }