ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/readable.C
Revision: 1.17
Committed: Sat Jan 6 14:42:29 2007 UTC (17 years, 4 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.16: +1 -0 lines
Log Message:
added some copyrights

File Contents

# User Rev Content
1 elmex 1.1 /*
2     CrossFire, A Multiplayer game for X-windows
3    
4 pippijn 1.17 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 elmex 1.1 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 root 1.9 The authors can be reached via e-mail at <crossfire@schmorp.de>
23 elmex 1.1 */
24    
25    
26     /* This file contains code relevant to the BOOKS hack -- designed
27     * to allow randomly occuring messages in non-magical texts.
28     */
29    
30     /* laid down initial file - dec 1995. -b.t. thomas@astro.psu.edu */
31    
32     #include <global.h>
33     #include <book.h>
34     #include <living.h>
35     #include <spells.h>
36    
37    
38     /* Define this if you want to archive book titles by contents.
39     * This option should enforce UNIQUE combinations of titles,authors and
40     * msg contents during and *between* game sessions.
41     * Note: a slight degeneracy exists since books are archived based on an integer
42     * index value calculated from the message text (similar to alchemy formulae).
43     * Sometimes two widely different messages have the same index value (rare). In
44     * this case, it is possible to occasionally generate 2 books with same title and
45     * different message content. Not really a bug, but rather a feature. This action
46     * should keeps player on their toes ;).
47     * Also, note that there is *finite* space available for archiving message and titles.
48     * Once this space is used, books will stop being archived. Not a serious problem
49     * under the current regime, since there are generally fewer possible (random)
50     * messages than space available on the titlelists.
51     * One exception (for sure) are the monster messages. But no worries, you should
52     * see all of the monster info in some order (but not all possble combinations)
53     * before the monster titlelist space is run out. You can increase titlelist
54     * space by increasing the array sizes for the monster book_authours and book_names
55     * (see max_titles[] array and include/read.h). Since the unique_book algorthm is
56     * kinda stupid, this program *may* slow down program execution if defined (but I don't
57     * think its a significant problem, at least, I have no problems running this option
58     * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg
59     * combinations have been generated, unique_book isnt called anymore. It takes 5-10
60     * sessions for this to happen).
61     * Final note: the game remembers book/title/msg combinations from reading the
62     * file lib/bookarch. If you REMOVE this file, you will lose your archive. So
63     * be sure to copy it over to the new lib directory when you change versions.
64     * -b.t.
65     */
66    
67     /* This flag is useful to see what kind of output messages are created */
68 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     {"Gridle", GIRDLE},
194     {"Ring", RING},
195     {"Horn", HORN},
196     {"Missile Weapon", BOW},
197     {"Missile", ARROW},
198     {"Hand Weapon", WEAPON},
199     {"Artifact", SKILL},
200     {"Food", FOOD},
201     {"Body Armour", ARMOUR}
202 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_msgfile() - if not called before, initialise the info list
647 elmex 1.1 * reads the messages file into the list pointed to by first_msg
648     */
649    
650 root 1.5 static void
651 elmex 1.1 init_msgfile (void)
652     {
653 root 1.5 FILE *fp;
654     char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp;
655     int comp;
656     static int did_init_msgfile;
657    
658     if (did_init_msgfile)
659     return;
660     did_init_msgfile = 1;
661    
662     sprintf (fname, "%s/messages", settings.datadir);
663 pippijn 1.14 LOG (llevDebug, "Reading messages from %s...\n", fname);
664 root 1.5
665     if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL)
666     {
667     linked_char *tmp = NULL;
668    
669     while (fgets (buf, MAX_BUF, fp) != NULL)
670     {
671     if (*buf == '#')
672     continue;
673     if ((cp = strchr (buf, '\n')) != NULL)
674     *cp = '\0';
675     cp = buf;
676     while (*cp == ' ') /* Skip blanks */
677     cp++;
678     if (!strncmp (cp, "ENDMSG", 6))
679     {
680     if (strlen (msgbuf) > BOOK_BUF)
681     {
682     LOG (llevDebug, "Warning: this string exceeded max book buf size:");
683 pippijn 1.14 LOG (llevDebug, " %s\n", msgbuf);
684 root 1.5 }
685     tmp->name = msgbuf;
686     tmp->next = first_msg;
687     first_msg = tmp;
688     nrofmsg++;
689     continue;
690     }
691     else if (!strncmp (cp, "MSG", 3))
692     {
693     tmp = new linked_char;
694    
695     strcpy (msgbuf, " "); /* reset msgbuf for new message */
696     continue;
697     }
698     else if (!buf_overflow (msgbuf, cp, HUGE_BUF - 1))
699     {
700     strcat (msgbuf, cp);
701     strcat (msgbuf, "\n");
702 root 1.2 }
703 root 1.5 }
704     close_and_delete (fp, comp);
705     }
706 elmex 1.1
707     #ifdef BOOK_MSG_DEBUG
708 pippijn 1.14 LOG (llevDebug, "init_info_listfile() got %d messages.\n", nrofmsg);
709 elmex 1.1 #endif
710 root 1.5 LOG (llevDebug, "done.\n");
711 elmex 1.1 }
712    
713    
714 pippijn 1.16 /* init_book_archive() - if not called before, initialise the info list
715 elmex 1.1 * This reads in the bookarch file into memory. bookarch is the file
716     * created and updated across multiple runs of the program.
717     */
718    
719 root 1.5 static void
720 elmex 1.1 init_book_archive (void)
721     {
722 root 1.5 FILE *fp;
723     int comp, nroftitle = 0;
724     char buf[MAX_BUF], fname[MAX_BUF], *cp;
725     title *book = NULL;
726     titlelist *bl = get_empty_booklist ();
727     static int did_init_barch;
728    
729     if (did_init_barch)
730     return;
731 root 1.6
732 root 1.5 did_init_barch = 1;
733    
734     if (!booklist)
735     booklist = bl;
736    
737     sprintf (fname, "%s/bookarch", settings.localdir);
738     LOG (llevDebug, " Reading bookarch from %s...\n", fname);
739    
740     if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL)
741     {
742     int value, type = 0;
743     size_t i;
744    
745     while (fgets (buf, MAX_BUF, fp) != NULL)
746     {
747     if (*buf == '#')
748     continue;
749     if ((cp = strchr (buf, '\n')) != NULL)
750     *cp = '\0';
751     cp = buf;
752     while (*cp == ' ') /* Skip blanks */
753     cp++;
754     if (!strncmp (cp, "title", 4))
755     {
756     book = get_empty_book (); /* init new book entry */
757     book->name = strchr (cp, ' ') + 1;
758     type = -1;
759     nroftitle++;
760     continue;
761     }
762     if (!strncmp (cp, "authour", 4))
763     {
764     book->authour = strchr (cp, ' ') + 1;
765     }
766     if (!strncmp (cp, "arch", 4))
767     {
768     book->archname = strchr (cp, ' ') + 1;
769     }
770     else if (sscanf (cp, "level %d", &value))
771     {
772     book->level = (uint16) value;
773     }
774     else if (sscanf (cp, "type %d", &value))
775     {
776     type = (uint16) value;
777     }
778     else if (sscanf (cp, "size %d", &value))
779     {
780     book->size = (uint16) value;
781 root 1.2 }
782 root 1.5 else if (sscanf (cp, "index %d", &value))
783 root 1.2 {
784 root 1.5 book->msg_index = (uint16) value;
785     }
786     else if (!strncmp (cp, "end", 3))
787     { /* link it */
788     bl = get_titlelist (type);
789     book->next = bl->first_book;
790     bl->first_book = book;
791     bl->number++;
792 root 1.2 }
793 root 1.5 }
794 pippijn 1.14 LOG (llevDebug, "book archives(used/avail): \n");
795 root 1.5 for (bl = booklist, i = 0; bl != NULL && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++)
796     {
797 pippijn 1.15 LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]);
798 root 1.5 }
799     close_and_delete (fp, comp);
800     }
801 elmex 1.1
802     #ifdef BOOK_MSG_DEBUG
803 pippijn 1.15 LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle);
804 elmex 1.1 #endif
805 root 1.5 LOG (llevDebug, " done.\n");
806 elmex 1.1 }
807    
808     /* init_mon_info() - creates the linked list of pointers to
809     * monster archetype objects if not called previously
810     */
811    
812 root 1.5 static void
813 elmex 1.1 init_mon_info (void)
814     {
815 root 1.5 archetype *at;
816     static int did_init_mon_info = 0;
817 elmex 1.1
818 root 1.5 if (did_init_mon_info)
819     return;
820 root 1.11
821 root 1.5 did_init_mon_info = 1;
822    
823    
824     for (at = first_archetype; at != NULL; at = at->next)
825     {
826     if (QUERY_FLAG (&at->clone, FLAG_MONSTER) && (!QUERY_FLAG (&at->clone, FLAG_CHANGING) || QUERY_FLAG (&at->clone, FLAG_UNAGGRESSIVE)))
827     {
828 root 1.11 objectlink *mon = new objectlink;
829 root 1.5
830     mon->ob = &at->clone;
831     mon->next = first_mon_info;
832     first_mon_info = mon;
833     nrofmon++;
834     }
835     }
836 root 1.11
837 root 1.5 LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
838 elmex 1.1 }
839    
840    
841 pippijn 1.16 /* init_readable() - initialise linked lists utilized by
842 elmex 1.1 * message functions in tailor_readable_ob()
843     *
844 pippijn 1.16 * This is the function called by the main routine to initialise
845 elmex 1.1 * all the readable information.
846     */
847    
848 root 1.5 void
849 elmex 1.1 init_readable (void)
850     {
851 root 1.5 static int did_this;
852 elmex 1.1
853 root 1.5 if (did_this)
854     return;
855 root 1.11
856 root 1.5 did_this = 1;
857    
858 pippijn 1.14 LOG (llevDebug, "Initialising reading data...\n");
859 root 1.5 init_msgfile ();
860     init_book_archive ();
861     init_mon_info ();
862     LOG (llevDebug, " Done\n");
863 elmex 1.1
864     }
865    
866     /*****************************************************************************
867     *
868     * This is the start of the administrative functions when creating
869     * new books (ie, updating title and the like)
870     *
871     *****************************************************************************/
872    
873    
874     /* find_title() - Search the titlelist (based on msgtype) to see if
875     * book matches something already there. IF so, return that title.
876     */
877    
878 root 1.5 static title *
879 elmex 1.1 find_title (const object *book, int msgtype)
880     {
881 root 1.5 title *t = NULL;
882     titlelist *tl = get_titlelist (msgtype);
883     int length = strlen (book->msg);
884     int index = strtoint (book->msg);
885    
886     if (msgtype < 0)
887     return (title *) NULL;
888    
889     if (tl)
890     t = tl->first_book;
891 root 1.6
892 root 1.5 while (t)
893     if (t->size == length && t->msg_index == index)
894     break;
895     else
896     t = t->next;
897 elmex 1.1
898     #ifdef ARCHIVE_DEBUG
899 root 1.5 if (t)
900     LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
901 elmex 1.1 #endif
902    
903 root 1.5 return t;
904 elmex 1.1 }
905    
906     /* new_text_name() - Only for objects of type BOOK. SPELLBOOK stuff is
907     * handled directly in change_book_name(). Names are based on text
908     * msgtype
909     * this sets book book->name based on msgtype given. What name
910     * is given is based on various criteria
911     */
912    
913 root 1.5 static void
914 elmex 1.1 new_text_name (object *book, int msgtype)
915     {
916 root 1.5 int nbr;
917     char name[MAX_BUF];
918 elmex 1.1
919 root 1.5 if (book->type != BOOK)
920     return;
921 elmex 1.1
922 root 1.5 switch (msgtype)
923     {
924     case 1: /*monster */
925 root 1.2 nbr = sizeof (mon_book_name) / sizeof (char *);
926     strcpy (name, mon_book_name[RANDOM () % nbr]);
927     break;
928 root 1.5 case 2: /*artifact */
929 root 1.2 nbr = sizeof (art_book_name) / sizeof (char *);
930     strcpy (name, art_book_name[RANDOM () % nbr]);
931     break;
932 root 1.5 case 3: /*spellpath */
933 root 1.2 nbr = sizeof (path_book_name) / sizeof (char *);
934     strcpy (name, path_book_name[RANDOM () % nbr]);
935     break;
936 root 1.5 case 4: /*alchemy */
937 root 1.2 nbr = sizeof (formula_book_name) / sizeof (char *);
938     strcpy (name, formula_book_name[RANDOM () % nbr]);
939     break;
940 root 1.5 case 5: /*gods */
941 root 1.2 nbr = sizeof (gods_book_name) / sizeof (char *);
942     strcpy (name, gods_book_name[RANDOM () % nbr]);
943     break;
944 root 1.5 case 6: /*msg file */
945     default:
946 root 1.2 if (book->weight > 2000)
947 root 1.5 { /* based on weight */
948     nbr = sizeof (heavy_book_name) / sizeof (char *);
949     strcpy (name, heavy_book_name[RANDOM () % nbr]);
950 root 1.2 }
951     else if (book->weight < 2001)
952     {
953 root 1.5 nbr = sizeof (light_book_name) / sizeof (char *);
954     strcpy (name, light_book_name[RANDOM () % nbr]);
955 root 1.2 }
956     break;
957 root 1.5 }
958 root 1.3
959 root 1.5 book->name = name;
960 elmex 1.1 }
961    
962     /* add_book_author()
963     * A lot like new_text_name above, but instead chooses an author
964     * and sets op->title to that value
965     */
966    
967 root 1.5 static void
968 elmex 1.1 add_author (object *op, int msgtype)
969     {
970 root 1.5 char title[MAX_BUF], name[MAX_BUF];
971     int nbr = sizeof (book_author) / sizeof (char *);
972 elmex 1.1
973 root 1.5 if (msgtype < 0 || strlen (op->msg) < 5)
974     return;
975 elmex 1.1
976 root 1.5 switch (msgtype)
977     {
978     case 1: /* monster */
979 root 1.2 nbr = sizeof (mon_author) / sizeof (char *);
980     strcpy (name, mon_author[RANDOM () % nbr]);
981     break;
982 root 1.5 case 2: /* artifacts */
983 root 1.2 nbr = sizeof (art_author) / sizeof (char *);
984     strcpy (name, art_author[RANDOM () % nbr]);
985     break;
986 root 1.5 case 3: /* spellpath */
987 root 1.2 nbr = sizeof (path_author) / sizeof (char *);
988     strcpy (name, path_author[RANDOM () % nbr]);
989     break;
990 root 1.5 case 4: /* alchemy */
991 root 1.2 nbr = sizeof (formula_author) / sizeof (char *);
992     strcpy (name, formula_author[RANDOM () % nbr]);
993     break;
994 root 1.5 case 5: /* gods */
995 root 1.2 nbr = sizeof (gods_author) / sizeof (char *);
996     strcpy (name, gods_author[RANDOM () % nbr]);
997     break;
998 root 1.5 case 6: /* msg file */
999     default:
1000 root 1.2 strcpy (name, book_author[RANDOM () % nbr]);
1001 root 1.5 }
1002 elmex 1.1
1003 root 1.5 sprintf (title, "of %s", name);
1004     op->title = title;
1005 elmex 1.1 }
1006    
1007     /* unique_book() - check to see if the book title/msg is unique. We
1008     * go through the entire list of possibilities each time. If we find
1009     * a match, then unique_book returns true (because inst unique).
1010     */
1011    
1012 root 1.5 static int
1013 elmex 1.1 unique_book (const object *book, int msgtype)
1014     {
1015 root 1.5 title *test;
1016 elmex 1.1
1017 root 1.5 if (!booklist)
1018     return 1; /* No archival entries! Must be unique! */
1019 elmex 1.1
1020 root 1.5 /* Go through the booklist. If the author and name match, not unique so
1021     * return 0.
1022     */
1023     for (test = get_titlelist (msgtype)->first_book; test; test = test->next)
1024     {
1025     if (!strcmp (test->name, book->name) && !strcmp (book->title, test->authour))
1026     return 0;
1027 elmex 1.1 }
1028 root 1.5 return 1;
1029 elmex 1.1 }
1030    
1031     /* add_book_to_list() */
1032    
1033 root 1.5 static void
1034 elmex 1.1 add_book_to_list (const object *book, int msgtype)
1035     {
1036 root 1.5 titlelist *tl = get_titlelist (msgtype);
1037     title *t;
1038 elmex 1.1
1039 root 1.5 if (!tl)
1040     {
1041     LOG (llevError, "add_book_to_list can't get booklist!\n");
1042     return;
1043     }
1044 elmex 1.1
1045 root 1.5 t = get_empty_book ();
1046     t->name = book->name;
1047     t->authour = book->title;
1048     t->size = strlen (book->msg);
1049     t->msg_index = strtoint (book->msg);
1050     t->archname = book->arch->name;
1051     t->level = book->level;
1052    
1053     t->next = tl->first_book;
1054     tl->first_book = t;
1055     tl->number++;
1056 elmex 1.1
1057 root 1.5 /* We have stuff we need to write now */
1058     need_to_write_bookarchive = 1;
1059 elmex 1.1
1060     #ifdef ARCHIVE_DEBUG
1061 root 1.5 LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
1062 elmex 1.1 #endif
1063    
1064     }
1065    
1066    
1067     /* change_book() - give a new, fancier name to generated
1068     * objects of type BOOK and SPELLBOOK.
1069     * Aug 96 I changed this so we will attempt to create consistent
1070     * authour/title and message content for BOOKs. Also, we will
1071     * alter books that match archive entries to the archival
1072     * levels and architypes. -b.t.
1073     */
1074    
1075     #define MAX_TITLE_CHECK 20
1076    
1077 root 1.5 void
1078 elmex 1.1 change_book (object *book, int msgtype)
1079     {
1080 root 1.5 int nbr = sizeof (book_descrpt) / sizeof (char *);
1081 elmex 1.1
1082 root 1.5 switch (book->type)
1083     {
1084     case BOOK:
1085 root 1.2 {
1086 root 1.5 titlelist *tl = get_titlelist (msgtype);
1087     title *t = NULL;
1088     int tries = 0;
1089    
1090     /* look to see if our msg already been archived. If so, alter
1091     * the book to match the archival text. If we fail to match,
1092     * then we archive the new title/name/msg combo if there is
1093     * room on the titlelist.
1094     */
1095 root 1.2
1096 root 1.5 if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype)))
1097     {
1098     object *tmpbook;
1099 root 1.2
1100 root 1.5 /* alter book properties */
1101     if ((tmpbook = get_archetype (t->archname)) != NULL)
1102     {
1103     tmpbook->msg = book->msg;
1104 root 1.13 tmpbook->copy_to (book);
1105     tmpbook->destroy ();
1106 root 1.5 }
1107 root 1.2
1108 root 1.5 book->title = t->authour;
1109     book->name = t->name;
1110     book->level = t->level;
1111     }
1112     /* Don't have any default title, so lets make up a new one */
1113     else
1114     {
1115     int numb, maxnames = max_titles[msgtype];
1116     const char *old_title;
1117     const char *old_name;
1118    
1119     old_title = book->title;
1120     old_name = book->name;
1121    
1122     /* some pre-generated books have title already set (from
1123     * maps), also don't bother looking for unique title if
1124     * we already used up all the available names! */
1125 root 1.2
1126 root 1.5 if (!tl)
1127     {
1128     LOG (llevError, "change_book_name(): can't find title list\n");
1129     numb = 0;
1130     }
1131     else
1132     numb = tl->number;
1133 elmex 1.1
1134 root 1.5 if (numb == maxnames)
1135     {
1136 elmex 1.1 #ifdef ARCHIVE_DEBUG
1137 root 1.5 LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1138 elmex 1.1 #endif
1139 root 1.5 break;
1140     }
1141     /* shouldnt change map-maker books */
1142     else if (!book->title)
1143     do
1144     {
1145     /* random book name */
1146     new_text_name (book, msgtype);
1147     add_author (book, msgtype); /* random author */
1148     tries++;
1149     }
1150     while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK);
1151    
1152     /* Now deal with 2 cases.
1153     * 1)If no space for a new title exists lets just restore
1154     * the old book properties. Remember, if the book had
1155     * matchd an older entry on the titlelist, we shouldnt
1156     * have called this routine in the first place!
1157     * 2) If we got a unique title, we need to add it to
1158     * the list.
1159     */
1160 elmex 1.1
1161 root 1.5 if (tries == MAX_TITLE_CHECK || numb == maxnames)
1162     { /* got to check maxnames again */
1163 elmex 1.1 #ifdef ARCHIVE_DEBUG
1164 root 1.5 LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1165 elmex 1.1 #endif
1166 root 1.5 /* restore old book properties here */
1167     book->title = old_title;
1168    
1169     if (RANDOM () % 4)
1170     {
1171     /* Lets give the book a description to individualize it some */
1172     char new_name[MAX_BUF];
1173    
1174     snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM () % nbr], old_name);
1175 root 1.2
1176 root 1.5 book->name = new_name;
1177     }
1178     else
1179     {
1180     book->name = old_name;
1181 root 1.2 }
1182 root 1.5 }
1183     else if (book->title && strlen (book->msg) > 5)
1184     { /* archive if long msg texts */
1185     add_book_to_list (book, msgtype);
1186     }
1187     }
1188     break;
1189 root 1.2 }
1190 elmex 1.1
1191 root 1.5 default:
1192 root 1.2 LOG (llevError, "change_book_name() called w/ illegal obj type.\n");
1193     return;
1194 root 1.5 }
1195 elmex 1.1 }
1196    
1197     /*****************************************************************************
1198     *
1199     * This is the start of the area that generates the actual contents
1200     * of the book.
1201     *
1202     *****************************************************************************/
1203    
1204     /*****************************************************************************
1205     * Monster msg generation code.
1206     ****************************************************************************/
1207    
1208     /* get_random_mon() - returns a random monster slected from linked
1209     * list of all monsters in the current game. If level is non-zero,
1210     * then only monsters greater than that level will be returned.
1211     * Changed 971225 to be greater than equal to level passed. Also
1212     * made choosing by level more random.
1213     */
1214    
1215     object *
1216     get_random_mon (int level)
1217     {
1218 root 1.5 objectlink *mon = first_mon_info;
1219     int i = 0, monnr;
1220    
1221     /* safety check. Problem w/ init_mon_info list? */
1222     if (!nrofmon || !mon)
1223     return (object *) NULL;
1224    
1225     if (!level)
1226     {
1227     /* lets get a random monster from the mon_info linked list */
1228     monnr = RANDOM () % nrofmon;
1229 elmex 1.1
1230 root 1.5 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1231     if (i++ == monnr)
1232     break;
1233    
1234     if (!mon)
1235     {
1236     LOG (llevError, "get_random_mon: Didn't find a monster when we should have\n");
1237 root 1.2 return NULL;
1238 root 1.5 }
1239     return mon->ob;
1240     }
1241 elmex 1.1
1242 root 1.5 /* Case where we are searching by level. Redone 971225 to be clearer
1243     * and more random. Before, it looks like it took a random monster from
1244     * the list, and then returned the first monster after that which was
1245     * appropriate level. This wasn't very random because if you had a
1246     * bunch of low level monsters and then a high level one, if the random
1247     * determine took one of the low level ones, it would just forward to the
1248     * high level one and return that. Thus, monsters that immediatly followed
1249     * a bunch of low level monsters would be more heavily returned. It also
1250     * means some of the dragons would be poorly represented, since they
1251     * are a group of high level monsters all around each other.
1252     */
1253    
1254     /* First count number of monsters meeting level criteria */
1255     for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1256     if (mon->ob->level >= level)
1257     i++;
1258    
1259     if (i == 0)
1260     {
1261     LOG (llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1262     return NULL;
1263     }
1264    
1265     monnr = RANDOM () % i;
1266     for (mon = first_mon_info; mon; mon = mon->next)
1267     if (mon->ob->level >= level && monnr-- == 0)
1268     return mon->ob;
1269    
1270     if (!mon)
1271     {
1272     LOG (llevError, "get_random_mon(): didn't find a monster when we should have\n");
1273     return NULL;
1274     }
1275     return NULL; /* Should be unreached, by keeps warnings down */
1276 elmex 1.1 }
1277    
1278     /*
1279     * Returns a description of the monster. This really needs to be
1280     * redone, as describe_item really gives a pretty internal description.
1281     */
1282    
1283 root 1.5 char *
1284 elmex 1.1 mon_desc (const object *mon)
1285     {
1286 root 1.5 static char retbuf[HUGE_BUF];
1287 elmex 1.1
1288 root 1.5 sprintf (retbuf, " *** %s ***\n", &mon->name);
1289     strcat (retbuf, describe_item (mon, NULL));
1290 elmex 1.1
1291 root 1.5 return retbuf;
1292 elmex 1.1 }
1293    
1294    
1295     /* This function returns the next monsters after 'tmp'. If no match is
1296     * found, it returns NULL (changed 0.94.3 to do this, since the
1297     * calling function (mon_info_msg) seems to expect that.
1298     */
1299    
1300     object *
1301     get_next_mon (object *tmp)
1302     {
1303 root 1.5 objectlink *mon;
1304 elmex 1.1
1305 root 1.5 for (mon = first_mon_info; mon; mon = mon->next)
1306     if (mon->ob == tmp)
1307     break;
1308    
1309     /* didn't find a match */
1310     if (!mon)
1311     return NULL;
1312     if (mon->next)
1313     return mon->next->ob;
1314     else
1315     return first_mon_info->ob;
1316 elmex 1.1
1317     }
1318    
1319    
1320    
1321     /* mon_info_msg() - generate a message detailing the properties
1322     * of a randomly selected monster.
1323     */
1324    
1325 root 1.5 char *
1326 elmex 1.1 mon_info_msg (int level, int booksize)
1327     {
1328 root 1.5 static char retbuf[BOOK_BUF];
1329     char tmpbuf[HUGE_BUF];
1330     object *tmp;
1331    
1332     /*preamble */
1333     strcpy (retbuf, "This beastiary contains:");
1334    
1335     /* lets print info on as many monsters as will fit in our
1336     * document.
1337     * 8-96 Had to change this a bit, otherwise there would
1338     * have been an impossibly large number of combinations
1339     * of text! (and flood out the available number of titles
1340     * in the archive in a snap!) -b.t.
1341     */
1342     tmp = get_random_mon (level * 3);
1343     while (tmp)
1344     {
1345     /* monster description */
1346     sprintf (tmpbuf, "\n---\n%s", mon_desc (tmp));
1347    
1348     if (!book_overflow (retbuf, tmpbuf, booksize))
1349     strcat (retbuf, tmpbuf);
1350     else
1351     break;
1352 elmex 1.1
1353 root 1.5 /* Note that the value this returns is not based on level */
1354     tmp = get_next_mon (tmp);
1355 elmex 1.1 }
1356    
1357     #ifdef BOOK_MSG_DEBUG
1358 root 1.5 LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf));
1359     fprintf (logfile, " MADE THIS:\n%s\n", retbuf);
1360 elmex 1.1 #endif
1361    
1362 root 1.5 return retbuf;
1363 elmex 1.1 }
1364    
1365    
1366     /*****************************************************************************
1367     * Artifact msg generation code.
1368     ****************************************************************************/
1369    
1370     /* artifact_msg() - generate a message detailing the properties
1371     * of 1-6 artifacts drawn sequentially from the artifact list.
1372     */
1373    
1374 root 1.5 char *
1375 elmex 1.1 artifact_msg (int level, int booksize)
1376     {
1377 root 1.5 artifactlist *al = NULL;
1378     artifact *art;
1379     int chance, i, type, index;
1380     int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1;
1381     char *ch, name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF];
1382     static char retbuf[BOOK_BUF];
1383     object *tmp = NULL;
1384    
1385     /* values greater than 5 create msg buffers that are too big! */
1386     if (book_entries > 5)
1387     book_entries = 5;
1388    
1389     /* lets determine what kind of artifact type randomly.
1390     * Right now legal artifacts only come from those listed
1391     * in art_name_array. Also, we check to be sure an artifactlist
1392     * for that type exists!
1393     */
1394     i = 0;
1395     do
1396     {
1397     index = RANDOM () % (sizeof (art_name_array) / sizeof (arttypename));
1398     type = art_name_array[index].type;
1399     al = find_artifactlist (type);
1400     i++;
1401     }
1402     while ((al == NULL) && (i < 10));
1403    
1404     if (i == 10) /* Unable to find a message */
1405     return ("None");
1406 elmex 1.1
1407 root 1.5 /* There is no reason to start on the artifact list at the begining. Lets
1408     * take our starting position randomly... */
1409     art = al->items;
1410     for (i = RANDOM () % level + RANDOM () % 2 + 1; i > 0; i--)
1411     {
1412     if (art == NULL)
1413     art = al->items; /* hmm, out of stuff, loop back around */
1414     art = art->next;
1415     }
1416    
1417     /* the base 'generic' name for our artifact */
1418     strcpy (name, art_name_array[index].name);
1419    
1420     /* Ok, lets print out the contents */
1421     sprintf (retbuf, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1422    
1423     /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1424     * as long as we have space up to the allowed max # (book_entires)
1425     */
1426     while (book_entries > 0)
1427     {
1428    
1429     if (art == NULL)
1430     art = al->items;
1431 elmex 1.1
1432 root 1.5 /* separator of items */
1433     strcpy (buf, "--- \n");
1434    
1435     /* Name */
1436     if (art->allowed != NULL && strcmp (art->allowed->name, "All"))
1437     {
1438     linked_char *temp, *next = art->allowed;
1439    
1440     do
1441 root 1.2 {
1442 root 1.5 temp = next;
1443     next = next->next;
1444 root 1.2 }
1445 root 1.5 while (next && !RANDOM () % 2);
1446     sprintf (buf, "%s A %s of %s", buf, &temp->name, &art->item->name);
1447     }
1448     else /* default name is used */
1449     sprintf (buf, "%s The %s of %s", buf, name, &art->item->name);
1450 root 1.2
1451 root 1.5 /* chance of finding */
1452     chance = (int) (100 * ((float) art->chance / al->total_chance));
1453     if (chance >= 20)
1454     sprintf (sbuf, "an uncommon");
1455     else if (chance >= 10)
1456     sprintf (sbuf, "an unusual");
1457     else if (chance >= 5)
1458     sprintf (sbuf, "a rare");
1459     else
1460     sprintf (sbuf, "a very rare");
1461     sprintf (buf, "%s is %s\n", buf, sbuf);
1462    
1463     /* value of artifact */
1464     sprintf (buf, "%s item with a value that is %d times normal.\n", buf, art->item->value);
1465    
1466     /* include the message about the artifact, if exists, and book
1467     * level is kinda high */
1468     if (art->item->msg && (RANDOM () % 4 + 1) < level && !((strlen (art->item->msg) + strlen (buf)) > BOOK_BUF))
1469     strcat (buf, art->item->msg);
1470    
1471     /* properties of the artifact */
1472 root 1.13 tmp = object::create ();
1473 root 1.5 add_abilities (tmp, art->item);
1474     tmp->type = type;
1475     SET_FLAG (tmp, FLAG_IDENTIFIED);
1476     if ((ch = describe_item (tmp, NULL)) != NULL && strlen (ch) > 1)
1477     sprintf (buf, "%s Properties of this artifact include: \n %s \n", buf, ch);
1478 root 1.13 tmp->destroy ();
1479 root 1.5 /* add the buf if it will fit */
1480     if (!book_overflow (retbuf, buf, booksize))
1481     strcat (retbuf, buf);
1482     else
1483     break;
1484 root 1.2
1485 root 1.5 art = art->next;
1486     book_entries--;
1487     }
1488 elmex 1.1
1489     #ifdef BOOK_MSG_DEBUG
1490 root 1.5 LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf));
1491     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1492 elmex 1.1 #endif
1493 root 1.5 return retbuf;
1494 elmex 1.1 }
1495    
1496     /*****************************************************************************
1497     * Spellpath message generation
1498     *****************************************************************************/
1499    
1500     /* spellpath_msg() - generate a message detailing the member
1501     * incantations/prayers (and some of their properties) belonging to
1502     * a given spellpath.
1503     */
1504    
1505 root 1.5 char *
1506 elmex 1.1 spellpath_msg (int level, int booksize)
1507     {
1508 root 1.5 static char retbuf[BOOK_BUF];
1509     char tmpbuf[BOOK_BUF];
1510     int path = RANDOM () % NRSPELLPATHS, prayers = RANDOM () % 2;
1511     int did_first_sp = 0;
1512     uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path];
1513     archetype *at;
1514    
1515     /* Preamble */
1516     sprintf (retbuf, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
1517    
1518     if (path == -1)
1519     strcat (retbuf, "having no known spell path.\n");
1520     else
1521     sprintf (retbuf, "%sbelonging to the path of %s:\n", retbuf, spellpathnames[path]);
1522    
1523     for (at = first_archetype; at != NULL; at = at->next)
1524     {
1525     /* Determine if this is an appropriate spell. Must
1526     * be of matching path, must be of appropriate type (prayer
1527     * or not), and must be within the valid level range.
1528     */
1529     if (at->clone.type == SPELL && at->clone.path_attuned & pnum &&
1530     ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers)) && (at->clone.level < (level * 8)))
1531     {
1532     strcpy (tmpbuf, at->clone.name);
1533 elmex 1.1
1534 root 1.5 if (book_overflow (retbuf, tmpbuf, booksize))
1535     break;
1536     else
1537     {
1538     if (did_first_sp)
1539     strcat (retbuf, ",\n");
1540     did_first_sp = 1;
1541     strcat (retbuf, tmpbuf);
1542 root 1.2 }
1543 root 1.5 }
1544 elmex 1.1 }
1545 root 1.5 /* Geez, no spells were generated. */
1546     if (!did_first_sp)
1547     {
1548     if (RANDOM () % 4) /* usually, lets make a recursive call... */
1549     spellpath_msg (level, booksize);
1550     else /* give up, cause knowing no spells exist for path is info too. */
1551     strcat (retbuf, "\n - no known spells exist -\n");
1552 elmex 1.1 }
1553 root 1.5 else
1554     {
1555     strcat (retbuf, "\n");
1556 elmex 1.1 }
1557 root 1.5 return retbuf;
1558 elmex 1.1 }
1559    
1560    
1561    
1562     /* formula_msg() - generate a message detailing the properties
1563     * of a randomly selected alchemical formula.
1564     */
1565    
1566 root 1.5 void
1567     make_formula_book (object *book, int level)
1568     {
1569     char retbuf[BOOK_BUF], title[MAX_BUF];
1570     recipelist *fl;
1571     recipe *formula = NULL;
1572     int chance;
1573    
1574     /* the higher the book level, the more complex (ie number of
1575     * ingredients) the formula can be.
1576     */
1577     fl = get_formulalist (((RANDOM () % level) / 3) + 1);
1578    
1579     if (!fl)
1580     fl = get_formulalist (1); /* safety */
1581    
1582     if (fl->total_chance == 0)
1583     {
1584     book->msg = "<indecipherable text>\n";
1585     new_text_name (book, 4);
1586     add_author (book, 4);
1587     return;
1588     }
1589    
1590     /* get a random formula, weighted by its bookchance */
1591     chance = RANDOM () % fl->total_chance;
1592     for (formula = fl->items; formula != NULL; formula = formula->next)
1593     {
1594     chance -= formula->chance;
1595     if (chance <= 0)
1596     break;
1597     }
1598    
1599     if (!formula || formula->arch_names <= 0)
1600     {
1601     book->msg = "<indecipherable text>\n";
1602     new_text_name (book, 4);
1603     add_author (book, 4);
1604    
1605 elmex 1.1 }
1606 root 1.5 else
1607     {
1608     /* looks like a formula was found. Base the amount
1609     * of information on the booklevel and the spellevel
1610     * of the formula. */
1611    
1612     const char *op_name = formula->arch_name[RANDOM () % formula->arch_names];
1613     archetype *at;
1614    
1615     /* preamble */
1616     sprintf (retbuf, "Herein is described a project using %s: \n", formula->skill ? &formula->skill : "an unknown skill");
1617    
1618 root 1.8 if ((at = archetype::find (op_name)) != (archetype *) NULL)
1619 root 1.5 op_name = at->clone.name;
1620     else
1621     LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1622 elmex 1.1
1623 root 1.5 /* item name */
1624     if (strcmp (formula->title, "NONE"))
1625     {
1626     sprintf (retbuf, "%sThe %s of %s", retbuf, op_name, &formula->title);
1627     /* This results in things like pile of philo. sulfur.
1628     * while philo. sulfur may look better, without this,
1629     * you get things like 'the wise' because its missing the
1630     * water of section.
1631     */
1632     sprintf (title, "%s: %s of %s",
1633     formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title);
1634 root 1.2 }
1635 root 1.5 else
1636 root 1.2 {
1637 root 1.5 sprintf (retbuf, "%sThe %s", retbuf, op_name);
1638     sprintf (title, "%s: %s", formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name);
1639     if (at->clone.title)
1640     {
1641     strcat (retbuf, " ");
1642     strcat (retbuf, at->clone.title);
1643     strcat (title, " ");
1644     strcat (title, at->clone.title);
1645 root 1.2 }
1646     }
1647 root 1.5 /* Lets name the book something meaningful ! */
1648     book->name = title;
1649     book->title = NULL;
1650 root 1.2
1651 root 1.5 /* ingredients to make it */
1652     if (formula->ingred != NULL)
1653 root 1.2 {
1654 root 1.5 linked_char *next;
1655     archetype *at;
1656 root 1.2
1657 root 1.8 at = archetype::find (formula->cauldron);
1658 root 1.2
1659 root 1.5 sprintf (retbuf + strlen (retbuf),
1660     " may be made at %s using the following ingredients:\n", at ? query_name (&at->clone) : "an unknown place");
1661 root 1.2
1662 root 1.5 for (next = formula->ingred; next != NULL; next = next->next)
1663 root 1.2 {
1664 root 1.5 strcat (retbuf, next->name);
1665     strcat (retbuf, "\n");
1666 root 1.2 }
1667     }
1668 root 1.5 else
1669     LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title);
1670     if (retbuf[strlen (retbuf) - 1] != '\n')
1671     strcat (retbuf, "\n");
1672 root 1.3
1673 root 1.5 book->msg = retbuf;
1674 elmex 1.1 }
1675     }
1676    
1677    
1678     /* msgfile_msg() - generate a message drawn randomly from a
1679     * file in lib/. Level currently has no effect on the message
1680     * which is returned.
1681     */
1682    
1683 root 1.5 char *
1684 elmex 1.1 msgfile_msg (int level, int booksize)
1685     {
1686 root 1.5 static char retbuf[BOOK_BUF];
1687     int i, msgnum;
1688     linked_char *msg = NULL;
1689    
1690     /* get a random message for the 'book' from linked list */
1691     if (nrofmsg > 1)
1692     {
1693     msg = first_msg;
1694     msgnum = RANDOM () % nrofmsg;
1695     for (i = 0; msg && i < nrofmsg && i != msgnum; i++)
1696     msg = msg->next;
1697     }
1698 elmex 1.1
1699 root 1.5 if (msg && !book_overflow (retbuf, msg->name, booksize))
1700     strcpy (retbuf, msg->name);
1701     else
1702     sprintf (retbuf, "\n <undecipherable text>");
1703 elmex 1.1
1704     #ifdef BOOK_MSG_DEBUG
1705 root 1.5 LOG (llevDebug, "\n info_list_msg() created strng: %d\n", strlen (retbuf));
1706     LOG (llevDebug, " MADE THIS:\n%s\n", retbuf);
1707 elmex 1.1 #endif
1708    
1709 root 1.5 return retbuf;
1710 elmex 1.1 }
1711    
1712    
1713     /* god_info_msg() - generate a message detailing the properties
1714     * of a random god. Used by the book hack. b.t.
1715     */
1716    
1717 root 1.5 const char *
1718 elmex 1.1 god_info_msg (int level, int booksize)
1719     {
1720 root 1.5 static char retbuf[BOOK_BUF];
1721     const char *name = NULL;
1722     char buf[BOOK_BUF];
1723     int i;
1724     size_t introlen;
1725     object *god = pntr_to_god_obj (get_rand_god ());
1726    
1727     if (!god)
1728     return (char *) NULL; /* oops, problems... */
1729     name = god->name;
1730    
1731     /* preamble.. */
1732     sprintf (retbuf, "This document contains knowledge concerning\n");
1733     sprintf (retbuf, "%sthe diety %s", retbuf, name);
1734    
1735     /* Always have as default information the god's descriptive terms. */
1736     if (nstrtok (god->msg, ",") > 0)
1737     {
1738     strcat (retbuf, ", known as");
1739     strcat (retbuf, strtoktolin (god->msg, ","));
1740     }
1741     else
1742     strcat (retbuf, "...");
1743    
1744     strcat (retbuf, "\n ---\n");
1745     introlen = strlen (retbuf); /* so we will know if no new info is added later */
1746 elmex 1.1
1747 root 1.5 /* Information about the god is random, and based on the level of the
1748     * 'book'. Probably there is a more intellegent way to implement
1749     * this ...
1750     */
1751    
1752     while (level > 0)
1753     {
1754     sprintf (buf, " ");
1755     if (level == 2 && RANDOM () % 2)
1756     { /* enemy god */
1757     const char *enemy = god->title;
1758 elmex 1.1
1759 root 1.5 if (enemy)
1760     sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy);
1761     }
1762     if (level == 3 && RANDOM () % 2)
1763     { /* enemy race, what the god's holy word effects */
1764     const char *enemy = god->slaying;
1765    
1766     if (enemy && !(god->path_denied & PATH_TURNING))
1767     if ((i = nstrtok (enemy, ",")) > 0)
1768     {
1769     char tmpbuf[MAX_BUF];
1770    
1771     sprintf (buf, "The holy words of %s have the power to\n", name);
1772     strcat (buf, "slay creatures belonging to the ");
1773     if (i > 1)
1774     sprintf (tmpbuf, "following \n races:%s", strtoktolin (enemy, ","));
1775     else
1776     sprintf (tmpbuf, "race of%s", strtoktolin (enemy, ","));
1777     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1778     }
1779     }
1780     if (level == 4 && RANDOM () % 2)
1781     { /* Priest of god gets these protect,vulnerable... */
1782     char tmpbuf[MAX_BUF], *cp;
1783    
1784     cp = describe_resistance (god, 1);
1785    
1786     if (*cp)
1787     { /* This god does have protections */
1788     sprintf (tmpbuf, "%s has a potent aura which is extended\n", name);
1789     strcat (tmpbuf, "faithful priests. The effects of this aura include:\n");
1790     strcat (tmpbuf, cp);
1791     strcat (buf, tmpbuf);
1792     strcat (buf, "\n ---\n");
1793     }
1794     else
1795     sprintf (buf, " ");
1796     }
1797     if (level == 5 && RANDOM () % 2)
1798     { /* aligned race, summoning */
1799     const char *race = god->race; /* aligned race */
1800    
1801     if (race && !(god->path_denied & PATH_SUMMON))
1802     if ((i = nstrtok (race, ",")) > 0)
1803     {
1804     char tmpbuf[MAX_BUF];
1805    
1806     sprintf (buf, "Creatures sacred to %s include the \n", name);
1807     if (i > 1)
1808     sprintf (tmpbuf, "following \n races:%s", strtoktolin (race, ","));
1809     else
1810     sprintf (tmpbuf, "race of%s", strtoktolin (race, ","));
1811     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1812     }
1813     }
1814     if (level == 6 && RANDOM () % 2)
1815     { /* blessing,curse properties of the god */
1816     char tmpbuf[MAX_BUF], *cp;
1817    
1818     cp = describe_resistance (god, 1);
1819    
1820     if (*cp)
1821     { /* This god does have protections */
1822     sprintf (tmpbuf, "\nThe priests of %s are known to be able to \n", name);
1823     strcat (tmpbuf, "bestow a blessing which makes the recipient\n");
1824     strcat (tmpbuf, cp);
1825     strcat (buf, tmpbuf);
1826     strcat (buf, "\n ---\n");
1827 root 1.2 }
1828 root 1.5 else
1829     sprintf (buf, " ");
1830    
1831     }
1832     if (level == 8 && RANDOM () % 2)
1833     { /* immunity, holy possession */
1834     int has_effect = 0, tmpvar;
1835     char tmpbuf[MAX_BUF];
1836    
1837     sprintf (tmpbuf, "\n");
1838     sprintf (tmpbuf, "The priests of %s are known to make cast a mighty \n", name);
1839    
1840     strcat (tmpbuf, "prayer of possession which gives the recipient\n");
1841    
1842     for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
1843     {
1844     if (god->resist[tmpvar] == 100)
1845     {
1846     has_effect = 1;
1847     sprintf (tmpbuf + strlen (tmpbuf), "Immunity to %s", attacktype_desc[tmpvar]);
1848 root 1.2 }
1849     }
1850 root 1.5 if (has_effect)
1851     {
1852     strcat (buf, tmpbuf);
1853     strcat (buf, "\n ---\n");
1854     }
1855     else
1856     sprintf (buf, " ");
1857     }
1858     if (level == 12 && RANDOM () % 2)
1859     { /* spell paths */
1860     int has_effect = 0, tmpvar;
1861     char tmpbuf[MAX_BUF];
1862    
1863     sprintf (tmpbuf, "\n");
1864     sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name);
1865     strcat (tmpbuf, "are mystically transformed. Effects of this include:\n");
1866     if ((tmpvar = god->path_attuned))
1867     {
1868     has_effect = 1;
1869     DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned");
1870 root 1.2 }
1871 root 1.5 if ((tmpvar = god->path_repelled))
1872     {
1873     has_effect = 1;
1874     DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled");
1875 root 1.2 }
1876 root 1.5 if ((tmpvar = god->path_denied))
1877     {
1878     has_effect = 1;
1879     DESCRIBE_PATH (tmpbuf, tmpvar, "Denied");
1880 root 1.2 }
1881 root 1.5 if (has_effect)
1882     {
1883     strcat (buf, tmpbuf);
1884     strcat (buf, "\n ---\n");
1885 root 1.2 }
1886 root 1.5 else
1887     sprintf (buf, " ");
1888     }
1889 root 1.2
1890 root 1.5 /* check to be sure new buffer size dont exceed either
1891     * the maximum buffer size, or the 'natural' size of the
1892     * book...
1893     */
1894     if (book_overflow (retbuf, buf, booksize))
1895     break;
1896     else if (strlen (buf) > 1)
1897     strcat (retbuf, buf);
1898     level--;
1899     }
1900     if (strlen (retbuf) == introlen)
1901     { /* we got no information beyond the preamble! */
1902     strcat (retbuf, " [Unfortunately the rest of the information is\n");
1903     strcat (retbuf, " hopelessly garbled!]\n ---\n");
1904     }
1905 elmex 1.1 #ifdef BOOK_MSG_DEBUG
1906 root 1.5 LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf));
1907     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1908 elmex 1.1 #endif
1909 root 1.5 return retbuf;
1910 elmex 1.1 }
1911    
1912     /* tailor_readable_ob()- The main routine. This chooses a random
1913     * message to put in given readable object (type==BOOK) which will
1914     * be referred hereafter as a 'book'. We use the book level to de-
1915     * termine the value of the information we will insert. Higher
1916     * values mean the book will (generally) have better/more info.
1917     * See individual cases as to how this will be utilized.
1918     * "Book" name/content length are based on the weight of the
1919     * document. If the value of msg_type is negative, we will randomly
1920     * choose the kind of message to generate.
1921     * -b.t. thomas@astro.psu.edu
1922     *
1923     * book is the object we are creating into.
1924     * If msg_type is a positive value, we use that to determine the
1925     * message type - otherwise a random value is used.
1926     *
1927     */
1928    
1929 root 1.5 void
1930 elmex 1.1 tailor_readable_ob (object *book, int msg_type)
1931     {
1932 root 1.5 char msgbuf[BOOK_BUF];
1933     int level = book->level ? (RANDOM () % book->level) + 1 : 1;
1934     int book_buf_size;
1935    
1936     /* safety */
1937     if (book->type != BOOK)
1938     return;
1939    
1940     if (level <= 0)
1941     return; /* if no level no point in doing any more... */
1942    
1943     /* Max text length this book can have. */
1944     book_buf_size = BOOKSIZE (book);
1945    
1946     /* &&& The message switch &&& */
1947     /* Below all of the possible types of messages in the "book"s.
1948     */
1949     /*
1950     * IF you add a new type of book msg, you will have to do several things.
1951     * 1) make sure there is an entry in the msg switch below!
1952     * 2) make sure there is an entry in max_titles[] array.
1953     * 3) make sure there are entries for your case in new_text_title()
1954     * and add_authour().
1955     * 4) you may want separate authour/book name arrays in read.h
1956     */
1957    
1958     msg_type = msg_type > 0 ? msg_type : (RANDOM () % 6);
1959     switch (msg_type)
1960     {
1961     case 1: /* monster attrib */
1962 root 1.2 strcpy (msgbuf, mon_info_msg (level, book_buf_size));
1963     break;
1964 root 1.5 case 2: /* artifact attrib */
1965 root 1.2 strcpy (msgbuf, artifact_msg (level, book_buf_size));
1966     break;
1967 root 1.5 case 3: /* grouping incantations/prayers by path */
1968 root 1.2 strcpy (msgbuf, spellpath_msg (level, book_buf_size));
1969     break;
1970 root 1.5 case 4: /* describe an alchemy formula */
1971     make_formula_book (book, level);
1972     /* make_formula_book already gives title */
1973     return;
1974     break;
1975     case 5: /* bits of information about a god */
1976 root 1.2 strcpy (msgbuf, god_info_msg (level, book_buf_size));
1977     break;
1978 root 1.5 case 0: /* use info list in lib/ */
1979     default:
1980 root 1.2 strcpy (msgbuf, msgfile_msg (level, book_buf_size));
1981     break;
1982 root 1.5 }
1983 elmex 1.1
1984 root 1.5 strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
1985 root 1.10
1986 root 1.5 if (strlen (msgbuf) > 1)
1987     {
1988     book->msg = msgbuf;
1989     /* lets give the "book" a new name, which may be a compound word */
1990     change_book (book, msg_type);
1991     }
1992 elmex 1.1
1993     }
1994    
1995    
1996     /*****************************************************************************
1997     *
1998     * Cleanup routine for readble stuff.
1999     *
2000     *****************************************************************************/
2001    
2002 root 1.5 void
2003 elmex 1.1 free_all_readable (void)
2004     {
2005 root 1.5 titlelist *tlist, *tnext;
2006     title *title1, *titlenext;
2007     linked_char *lmsg, *nextmsg;
2008     objectlink *monlink, *nextmon;
2009    
2010     LOG (llevDebug, "freeing all book information\n");
2011    
2012     for (tlist = booklist; tlist != NULL; tlist = tnext)
2013     {
2014     tnext = tlist->next;
2015    
2016     for (title1 = tlist->first_book; title1; title1 = titlenext)
2017     {
2018     titlenext = title1->next;
2019     delete title1;
2020     }
2021    
2022     delete tlist;
2023     }
2024 root 1.10
2025 root 1.5 for (lmsg = first_msg; lmsg; lmsg = nextmsg)
2026     {
2027     nextmsg = lmsg->next;
2028     delete lmsg;
2029     }
2030 root 1.10
2031 root 1.5 for (monlink = first_mon_info; monlink; monlink = nextmon)
2032     {
2033     nextmon = monlink->next;
2034 root 1.11 delete monlink;
2035 root 1.5 }
2036 elmex 1.1 }
2037    
2038    
2039     /*****************************************************************************
2040     *
2041     * Writeback routine for updating the bookarchive.
2042     *
2043     ****************************************************************************/
2044    
2045     /* write_book_archive() - write out the updated book archive */
2046    
2047 root 1.5 void
2048 elmex 1.1 write_book_archive (void)
2049     {
2050 root 1.5 FILE *fp;
2051     int index = 0;
2052     char fname[MAX_BUF];
2053     title *book = NULL;
2054     titlelist *bl = get_titlelist (0);
2055    
2056     /* If nothing changed, don't write anything */
2057     if (!need_to_write_bookarchive)
2058     return;
2059     need_to_write_bookarchive = 0;
2060    
2061     sprintf (fname, "%s/bookarch", settings.localdir);
2062     LOG (llevDebug, "Updating book archive: %s...\n", fname);
2063    
2064     if ((fp = fopen (fname, "w")) == NULL)
2065     {
2066     LOG (llevDebug, "Can't open book archive file %s\n", fname);
2067     }
2068     else
2069     {
2070     while (bl)
2071     {
2072     for (book = bl->first_book; book; book = book->next)
2073     if (book && book->authour)
2074     {
2075     fprintf (fp, "title %s\n", &book->name);
2076     fprintf (fp, "authour %s\n", &book->authour);
2077     fprintf (fp, "arch %s\n", &book->archname);
2078     fprintf (fp, "level %d\n", book->level);
2079     fprintf (fp, "type %d\n", index);
2080     fprintf (fp, "size %d\n", book->size);
2081     fprintf (fp, "index %d\n", book->msg_index);
2082     fprintf (fp, "end\n");
2083     }
2084     bl = bl->next;
2085     index++;
2086     }
2087     fclose (fp);
2088     chmod (fname, SAVE_MODE);
2089     }
2090     }
2091     readable_message_type *
2092     get_readable_message_type (object *readable)
2093     {
2094     uint8 subtype = readable->subtype;
2095    
2096     if (subtype > last_readable_subtype)
2097     return &(readable_message_types[0]);
2098     return &(readable_message_types[subtype]);
2099 elmex 1.1 }