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

# User Rev Content
1 elmex 1.1 /*
2 root 1.23 * CrossFire, A Multiplayer game
3 pippijn 1.18 *
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 elmex 1.1
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 root 1.5
69 elmex 1.1 /* #define BOOK_MSG_DEBUG */
70    
71     /* This flag is useful for debuging archiving action */
72 root 1.5
73 elmex 1.1 /* #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 root 1.6 struct title : zero_initialised
81 root 1.3 {
82 root 1.5 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 root 1.6 title *next;
89     };
90 elmex 1.1
91 root 1.6 struct titlelist : zero_initialised
92 root 1.3 {
93 root 1.5 int number; /* number of items in the list */
94 root 1.6 title *first_book; /* pointer to first book in this list */
95     titlelist *next; /* pointer to next book list */
96     };
97 elmex 1.1
98     /* special structure, used only by art_name_array[] */
99 root 1.6 struct arttypename
100 root 1.5 {
101     const char *name; /* generic name to call artifacts of this type */
102     int type; /* matching type */
103 root 1.6 };
104 elmex 1.1
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 root 1.5 static int nrofmon = 0, need_to_write_bookarchive = 0;
114 elmex 1.1
115    
116 pippijn 1.16 /* this is needed to keep track of status of initialisation
117 elmex 1.1 * 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 root 1.5 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 elmex 1.1 };
151    
152 root 1.5 static const char *const path_book_name[] = {
153     "codex",
154     "compendium",
155     "exposition",
156     "tables",
157     "treatise"
158 elmex 1.1 };
159    
160     /* used by spellpath texts */
161 root 1.5 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 elmex 1.1 };
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 root 1.5 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 root 1.20 {"Girdle", GIRDLE},
194 root 1.5 {"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 elmex 1.1 };
203    
204 root 1.5 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 elmex 1.1 };
217    
218     /* used by artifact texts */
219 root 1.5 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 elmex 1.1 };
228    
229     /*
230     * Monster book information
231     */
232    
233 root 1.5 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 elmex 1.1 };
248    
249    
250     /* used by monster beastuary texts */
251 root 1.5 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 elmex 1.1 };
266    
267     /*
268     * God book information
269     */
270    
271 root 1.5 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 elmex 1.1 };
283    
284     /* used by gods texts */
285 root 1.5 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 elmex 1.1 };
299    
300    
301     /*
302     * Alchemy (formula) information
303     */
304    
305 root 1.5 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 elmex 1.1 };
315    
316     /* this isn't used except for empty books */
317 root 1.5 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 elmex 1.1 };
333    
334     /*
335     * Generic book information
336     */
337    
338     /* used by msg file and 'generic' books */
339 root 1.5 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 elmex 1.1 };
354    
355 root 1.5 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 elmex 1.1 };
366    
367    
368     /* used by 'generic' books */
369 root 1.5 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 elmex 1.1 };
413    
414 root 1.5 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 elmex 1.1 };
434 root 1.5
435 elmex 1.1 /* 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 root 1.5 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 elmex 1.1 };
504 root 1.5 int last_readable_subtype = sizeof (readable_message_types) / sizeof (readable_message_type);
505 elmex 1.1
506 root 1.5 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 elmex 1.1 };
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 root 1.5 titlelist *bl = new titlelist;
525 root 1.3
526 root 1.5 bl->number = 0;
527     bl->first_book = NULL;
528     bl->next = NULL;
529     return bl;
530 elmex 1.1 }
531    
532 root 1.5 static title *
533 elmex 1.1 get_empty_book (void)
534     {
535 root 1.5 title *t = new title;
536 root 1.3
537 root 1.5 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 elmex 1.1 }
546    
547     /* get_titlelist() - returns pointer to the title list referanced by i */
548    
549     static titlelist *
550     get_titlelist (int i)
551     {
552 root 1.5 titlelist *tl = booklist;
553     int number = i;
554 elmex 1.1
555 root 1.5 if (number < 0)
556     return tl;
557 elmex 1.1
558 root 1.5 while (tl && number)
559     {
560     if (!tl->next)
561     tl->next = get_empty_booklist ();
562 root 1.6
563 root 1.5 tl = tl->next;
564     number--;
565     }
566 elmex 1.1
567 root 1.5 return tl;
568 elmex 1.1 }
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 root 1.5 int
578 elmex 1.1 nstrtok (const char *buf1, const char *buf2)
579     {
580 root 1.5 char *tbuf, sbuf[12], buf[MAX_BUF];
581     int number = 0;
582 elmex 1.1
583 root 1.5 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 elmex 1.1 }
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 root 1.5 char *
602 elmex 1.1 strtoktolin (const char *buf1, const char *buf2)
603     {
604 root 1.5 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 elmex 1.1 }
627    
628 root 1.5 int
629 elmex 1.1 book_overflow (const char *buf1, const char *buf2, int booksize)
630     {
631    
632 root 1.5 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 elmex 1.1
637    
638     }
639    
640     /*****************************************************************************
641     *
642 pippijn 1.16 * Start of initialisation related functions.
643 elmex 1.1 *
644     ****************************************************************************/
645    
646 pippijn 1.16 /* init_book_archive() - if not called before, initialise the info list
647 elmex 1.1 * This reads in the bookarch file into memory. bookarch is the file
648     * created and updated across multiple runs of the program.
649     */
650 root 1.5 static void
651 elmex 1.1 init_book_archive (void)
652     {
653 root 1.5 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 root 1.6
663 root 1.5 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 root 1.2 }
713 root 1.5 else if (sscanf (cp, "index %d", &value))
714 root 1.2 {
715 root 1.5 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 root 1.2 }
724 root 1.5 }
725 pippijn 1.14 LOG (llevDebug, "book archives(used/avail): \n");
726 root 1.5 for (bl = booklist, i = 0; bl != NULL && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++)
727     {
728 pippijn 1.15 LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]);
729 root 1.5 }
730     close_and_delete (fp, comp);
731     }
732 elmex 1.1
733     #ifdef BOOK_MSG_DEBUG
734 pippijn 1.15 LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle);
735 elmex 1.1 #endif
736 root 1.5 LOG (llevDebug, " done.\n");
737 elmex 1.1 }
738    
739     /* init_mon_info() - creates the linked list of pointers to
740     * monster archetype objects if not called previously
741     */
742    
743 root 1.5 static void
744 elmex 1.1 init_mon_info (void)
745     {
746 root 1.5 archetype *at;
747     static int did_init_mon_info = 0;
748 elmex 1.1
749 root 1.5 if (did_init_mon_info)
750     return;
751 root 1.11
752 root 1.5 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 root 1.11 objectlink *mon = new objectlink;
760 root 1.5
761     mon->ob = &at->clone;
762     mon->next = first_mon_info;
763     first_mon_info = mon;
764     nrofmon++;
765     }
766     }
767 root 1.11
768 root 1.5 LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
769 elmex 1.1 }
770    
771 pippijn 1.16 /* init_readable() - initialise linked lists utilized by
772 elmex 1.1 * message functions in tailor_readable_ob()
773     *
774 pippijn 1.16 * This is the function called by the main routine to initialise
775 elmex 1.1 * all the readable information.
776     */
777 root 1.5 void
778 elmex 1.1 init_readable (void)
779     {
780 root 1.5 static int did_this;
781 elmex 1.1
782 root 1.5 if (did_this)
783     return;
784 root 1.11
785 root 1.5 did_this = 1;
786    
787 pippijn 1.14 LOG (llevDebug, "Initialising reading data...\n");
788 root 1.5 init_book_archive ();
789     init_mon_info ();
790     LOG (llevDebug, " Done\n");
791 elmex 1.1 }
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 root 1.5 static title *
804 elmex 1.1 find_title (const object *book, int msgtype)
805     {
806 root 1.5 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 root 1.6
817 root 1.5 while (t)
818     if (t->size == length && t->msg_index == index)
819     break;
820     else
821     t = t->next;
822 elmex 1.1
823     #ifdef ARCHIVE_DEBUG
824 root 1.5 if (t)
825     LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
826 elmex 1.1 #endif
827    
828 root 1.5 return t;
829 elmex 1.1 }
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 root 1.5 static void
839 elmex 1.1 new_text_name (object *book, int msgtype)
840     {
841 root 1.5 int nbr;
842     char name[MAX_BUF];
843 elmex 1.1
844 root 1.5 if (book->type != BOOK)
845     return;
846 elmex 1.1
847 root 1.5 switch (msgtype)
848     {
849 root 1.21 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 root 1.5 }
883 root 1.3
884 root 1.5 book->name = name;
885 elmex 1.1 }
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 root 1.5 static void
893 elmex 1.1 add_author (object *op, int msgtype)
894     {
895 root 1.5 char title[MAX_BUF], name[MAX_BUF];
896     int nbr = sizeof (book_author) / sizeof (char *);
897 elmex 1.1
898 root 1.5 if (msgtype < 0 || strlen (op->msg) < 5)
899     return;
900 elmex 1.1
901 root 1.5 switch (msgtype)
902     {
903 root 1.21 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 root 1.5 }
927 elmex 1.1
928 root 1.5 sprintf (title, "of %s", name);
929     op->title = title;
930 elmex 1.1 }
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 root 1.5 static int
938 elmex 1.1 unique_book (const object *book, int msgtype)
939     {
940 root 1.5 title *test;
941 elmex 1.1
942 root 1.5 if (!booklist)
943     return 1; /* No archival entries! Must be unique! */
944 elmex 1.1
945 root 1.5 /* 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 elmex 1.1 }
953 root 1.5 return 1;
954 elmex 1.1 }
955    
956     /* add_book_to_list() */
957    
958 root 1.5 static void
959 elmex 1.1 add_book_to_list (const object *book, int msgtype)
960     {
961 root 1.5 titlelist *tl = get_titlelist (msgtype);
962     title *t;
963 elmex 1.1
964 root 1.5 if (!tl)
965     {
966     LOG (llevError, "add_book_to_list can't get booklist!\n");
967     return;
968     }
969 elmex 1.1
970 root 1.5 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 elmex 1.1
982 root 1.5 /* We have stuff we need to write now */
983     need_to_write_bookarchive = 1;
984 elmex 1.1
985     #ifdef ARCHIVE_DEBUG
986 root 1.5 LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
987 elmex 1.1 #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 root 1.5 void
1003 elmex 1.1 change_book (object *book, int msgtype)
1004     {
1005 root 1.5 int nbr = sizeof (book_descrpt) / sizeof (char *);
1006 elmex 1.1
1007 root 1.5 switch (book->type)
1008     {
1009     case BOOK:
1010 root 1.2 {
1011 root 1.5 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 root 1.2
1021 root 1.5 if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype)))
1022     {
1023     object *tmpbook;
1024 root 1.2
1025 root 1.5 /* alter book properties */
1026     if ((tmpbook = get_archetype (t->archname)) != NULL)
1027     {
1028     tmpbook->msg = book->msg;
1029 root 1.13 tmpbook->copy_to (book);
1030     tmpbook->destroy ();
1031 root 1.5 }
1032 root 1.2
1033 root 1.5 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 root 1.2
1051 root 1.5 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 elmex 1.1
1059 root 1.5 if (numb == maxnames)
1060     {
1061 elmex 1.1 #ifdef ARCHIVE_DEBUG
1062 root 1.5 LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1063 elmex 1.1 #endif
1064 root 1.5 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 elmex 1.1
1086 root 1.5 if (tries == MAX_TITLE_CHECK || numb == maxnames)
1087     { /* got to check maxnames again */
1088 elmex 1.1 #ifdef ARCHIVE_DEBUG
1089 root 1.5 LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1090 elmex 1.1 #endif
1091 root 1.5 /* 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 root 1.19 snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[rndm (nbr)], old_name);
1100 root 1.2
1101 root 1.5 book->name = new_name;
1102     }
1103     else
1104     {
1105     book->name = old_name;
1106 root 1.2 }
1107 root 1.5 }
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 root 1.2 }
1115 elmex 1.1
1116 root 1.5 default:
1117 root 1.2 LOG (llevError, "change_book_name() called w/ illegal obj type.\n");
1118     return;
1119 root 1.5 }
1120 elmex 1.1 }
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 root 1.5 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 elmex 1.1
1155 root 1.5 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 root 1.2 return NULL;
1163 root 1.5 }
1164     return mon->ob;
1165     }
1166 elmex 1.1
1167 root 1.5 /* 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 elmex 1.1 }
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 root 1.5 char *
1209 elmex 1.1 mon_desc (const object *mon)
1210     {
1211 root 1.5 static char retbuf[HUGE_BUF];
1212 elmex 1.1
1213 root 1.5 sprintf (retbuf, " *** %s ***\n", &mon->name);
1214     strcat (retbuf, describe_item (mon, NULL));
1215 elmex 1.1
1216 root 1.5 return retbuf;
1217 elmex 1.1 }
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 root 1.5 objectlink *mon;
1229 elmex 1.1
1230 root 1.5 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 elmex 1.1
1242     }
1243    
1244    
1245    
1246     /* mon_info_msg() - generate a message detailing the properties
1247     * of a randomly selected monster.
1248     */
1249    
1250 root 1.5 char *
1251 elmex 1.1 mon_info_msg (int level, int booksize)
1252     {
1253 root 1.5 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 elmex 1.1
1278 root 1.5 /* Note that the value this returns is not based on level */
1279     tmp = get_next_mon (tmp);
1280 elmex 1.1 }
1281    
1282     #ifdef BOOK_MSG_DEBUG
1283 root 1.5 LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf));
1284     fprintf (logfile, " MADE THIS:\n%s\n", retbuf);
1285 elmex 1.1 #endif
1286    
1287 root 1.5 return retbuf;
1288 elmex 1.1 }
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 root 1.22 const char *
1299 elmex 1.1 artifact_msg (int level, int booksize)
1300     {
1301 root 1.5 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 root 1.22 const char *ch;
1306     char name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF];
1307 root 1.5 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 root 1.22 return "None";
1331 elmex 1.1
1332 root 1.5 /* 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 root 1.21 assign (name, art_name_array[index].name);
1344 root 1.5
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 elmex 1.1
1357 root 1.5 /* 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 root 1.2 {
1367 root 1.5 temp = next;
1368     next = next->next;
1369 root 1.2 }
1370 root 1.5 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 root 1.2
1376 root 1.5 /* 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 root 1.13 tmp = object::create ();
1398 root 1.5 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 root 1.13 tmp->destroy ();
1404 root 1.5 /* add the buf if it will fit */
1405     if (!book_overflow (retbuf, buf, booksize))
1406     strcat (retbuf, buf);
1407     else
1408     break;
1409 root 1.2
1410 root 1.5 art = art->next;
1411     book_entries--;
1412     }
1413 elmex 1.1
1414     #ifdef BOOK_MSG_DEBUG
1415 root 1.5 LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf));
1416     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1417 elmex 1.1 #endif
1418 root 1.5 return retbuf;
1419 elmex 1.1 }
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 root 1.5 char *
1431 elmex 1.1 spellpath_msg (int level, int booksize)
1432     {
1433 root 1.5 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 root 1.21 assign (tmpbuf, at->clone.name);
1458 elmex 1.1
1459 root 1.5 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 root 1.2 }
1468 root 1.5 }
1469 elmex 1.1 }
1470 root 1.5 /* 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 elmex 1.1 }
1478 root 1.5 else
1479     {
1480     strcat (retbuf, "\n");
1481 elmex 1.1 }
1482 root 1.5 return retbuf;
1483 elmex 1.1 }
1484    
1485     /* formula_msg() - generate a message detailing the properties
1486     * of a randomly selected alchemical formula.
1487     */
1488 root 1.5 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 elmex 1.1 }
1528 root 1.5 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 root 1.8 if ((at = archetype::find (op_name)) != (archetype *) NULL)
1541 root 1.5 op_name = at->clone.name;
1542     else
1543     LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1544 elmex 1.1
1545 root 1.5 /* 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 root 1.2 }
1557 root 1.5 else
1558 root 1.2 {
1559 root 1.5 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 root 1.2 }
1568     }
1569 root 1.5 /* Lets name the book something meaningful ! */
1570     book->name = title;
1571     book->title = NULL;
1572 root 1.2
1573 root 1.5 /* ingredients to make it */
1574     if (formula->ingred != NULL)
1575 root 1.2 {
1576 root 1.5 linked_char *next;
1577     archetype *at;
1578 root 1.2
1579 root 1.8 at = archetype::find (formula->cauldron);
1580 root 1.2
1581 root 1.5 sprintf (retbuf + strlen (retbuf),
1582     " may be made at %s using the following ingredients:\n", at ? query_name (&at->clone) : "an unknown place");
1583 root 1.2
1584 root 1.5 for (next = formula->ingred; next != NULL; next = next->next)
1585 root 1.2 {
1586 root 1.5 strcat (retbuf, next->name);
1587     strcat (retbuf, "\n");
1588 root 1.2 }
1589     }
1590 root 1.5 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 root 1.3
1595 root 1.5 book->msg = retbuf;
1596 elmex 1.1 }
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 root 1.5 const char *
1603 elmex 1.1 god_info_msg (int level, int booksize)
1604     {
1605 root 1.5 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 elmex 1.1
1632 root 1.5 /* 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 elmex 1.1
1644 root 1.5 if (enemy)
1645     sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy);
1646     }
1647 root 1.22
1648 root 1.5 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 root 1.22
1667 root 1.5 if (level == 4 && RANDOM () % 2)
1668     { /* Priest of god gets these protect,vulnerable... */
1669 root 1.22 char tmpbuf[MAX_BUF];
1670 root 1.5
1671 root 1.22 if (const char *cp = describe_resistance (god, 1))
1672 root 1.5 { /* 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 root 1.22
1683 root 1.5 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 root 1.22
1701 root 1.5 if (level == 6 && RANDOM () % 2)
1702     { /* blessing,curse properties of the god */
1703 root 1.22 char tmpbuf[MAX_BUF];
1704 root 1.5
1705 root 1.22 if (const char *cp = describe_resistance (god, 1))
1706 root 1.5 { /* 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 root 1.2 }
1713 root 1.5 else
1714     sprintf (buf, " ");
1715    
1716     }
1717 root 1.22
1718 root 1.5 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 root 1.2 }
1735     }
1736 root 1.22
1737 root 1.5 if (has_effect)
1738     {
1739     strcat (buf, tmpbuf);
1740     strcat (buf, "\n ---\n");
1741     }
1742     else
1743     sprintf (buf, " ");
1744     }
1745 root 1.22
1746 root 1.5 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 root 1.22
1755 root 1.5 if ((tmpvar = god->path_attuned))
1756     {
1757     has_effect = 1;
1758     DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned");
1759 root 1.2 }
1760 root 1.22
1761 root 1.5 if ((tmpvar = god->path_repelled))
1762     {
1763     has_effect = 1;
1764     DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled");
1765 root 1.2 }
1766 root 1.22
1767 root 1.5 if ((tmpvar = god->path_denied))
1768     {
1769     has_effect = 1;
1770     DESCRIBE_PATH (tmpbuf, tmpvar, "Denied");
1771 root 1.2 }
1772 root 1.22
1773 root 1.5 if (has_effect)
1774     {
1775     strcat (buf, tmpbuf);
1776     strcat (buf, "\n ---\n");
1777 root 1.2 }
1778 root 1.5 else
1779     sprintf (buf, " ");
1780     }
1781 root 1.2
1782 root 1.5 /* 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 root 1.22
1791 root 1.5 level--;
1792     }
1793 root 1.22
1794 root 1.5 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 elmex 1.1 #ifdef BOOK_MSG_DEBUG
1800 root 1.5 LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf));
1801     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1802 elmex 1.1 #endif
1803 root 1.5 return retbuf;
1804 elmex 1.1 }
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 root 1.5 void
1823 elmex 1.1 tailor_readable_ob (object *book, int msg_type)
1824     {
1825 root 1.5 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 root 1.24 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 root 1.5 }
1876 elmex 1.1
1877 root 1.5 strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
1878 root 1.10
1879 root 1.5 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 elmex 1.1
1886     }
1887    
1888    
1889     /*****************************************************************************
1890     *
1891     * Cleanup routine for readble stuff.
1892     *
1893     *****************************************************************************/
1894    
1895 root 1.5 void
1896 elmex 1.1 free_all_readable (void)
1897     {
1898 root 1.5 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 root 1.10
1918 root 1.5 for (lmsg = first_msg; lmsg; lmsg = nextmsg)
1919     {
1920     nextmsg = lmsg->next;
1921     delete lmsg;
1922     }
1923 root 1.10
1924 root 1.5 for (monlink = first_mon_info; monlink; monlink = nextmon)
1925     {
1926     nextmon = monlink->next;
1927 root 1.11 delete monlink;
1928 root 1.5 }
1929 elmex 1.1 }
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 root 1.5 void
1941 elmex 1.1 write_book_archive (void)
1942     {
1943 root 1.5 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 elmex 1.1 }