ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/readable.C
Revision: 1.42
Committed: Thu Oct 15 16:00:37 2009 UTC (14 years, 7 months ago) by sf-marcmagus
Content type: text/plain
Branch: MAIN
Changes since 1.41: +14 -10 lines
Log Message:
Add inscribable arches for other book types.
Use 'container'/weight_limit to define capacity of inscribables in characters.
Add treasures/arches to specify books with/without text.
Scorn and Navar Public Libraries use these so they don't generate inscribables.
Fix bug allowing theft of blank books from libraries.
Fix bug preventing adding an adjective to a book name if the titles are used up.
Change error message on reading empty book to be more clear.
Change error message on failed inscription [too much text] to be more informative.
Looking at an inscribable will tell you what you can do with it/what its capacity is in a hint.
Fix broken debug statements in book generation.

File Contents

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