ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/readable.C
Revision: 1.25
Committed: Mon May 28 21:21:40 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.24: +17 -18 lines
Log Message:
update copyrights in common/*.C and util/*.C

File Contents

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