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

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.25 * This file is part of Crossfire TRT, the Multiplayer Online Role Playing Game.
3 pippijn 1.18 *
4 root 1.25 * Copyright (©) 2005,2006,2007 Marc Alexander Lehmann / Robin Redeker / the Crossfire TRT team
5     * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.18 *
8 root 1.25 * Crossfire TRT is free software; you can redistribute it and/or modify it
9     * under the terms of the GNU General Public License as published by the Free
10     * Software Foundation; either version 2 of the License, or (at your option)
11     * any later version.
12 pippijn 1.18 *
13 root 1.25 * This program is distributed in the hope that it will be useful, but
14     * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15     * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16     * for more details.
17 pippijn 1.18 *
18 root 1.25 * You should have received a copy of the GNU General Public License along
19     * with Crossfire TRT; if not, write to the Free Software Foundation, Inc. 51
20     * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21     *
22     * The authors can be reached via e-mail to <crossfire@schmorp.de>
23 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     /*subtype 0 */ {0, 0},
441     /* book messages subtypes */
442     /*subtype 1 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1},
443     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_2},
444     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_1},
445     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_2},
446     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_1},
447     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_2},
448     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_EVOKER},
449     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PRAYER},
450     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PYRO},
451     /*subtype 10 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER},
452     {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SUMMONER},
453     /* card messages subtypes */
454     {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_1},
455     {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_2},
456     {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_3},
457     {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_1},
458     {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_2},
459     {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_3},
460     {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_1},
461     {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_2},
462     /*subtype 20 */ {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3},
463     {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_1},
464     {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_2},
465     {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_3},
466    
467     /* Paper messages subtypes */
468     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_1},
469     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_2},
470     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_3},
471     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_1},
472     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_2},
473     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_1},
474     /*subtype 30 */ {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2},
475     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_1},
476     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_2},
477     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_1},
478     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_2},
479     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_1},
480     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_2},
481     {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_MAGIC},
482    
483     /* road signs messages subtypes */
484     {MSG_TYPE_SIGN, MSG_TYPE_SIGN_BASIC},
485     {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_LEFT},
486     /*subtype 40 */ {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT},
487     {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_BOTH},
488    
489     /* stones and monument messages */
490     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_1},
491     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_2},
492     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_3},
493     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_1},
494     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_2},
495     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_3},
496     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_1},
497     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_2},
498     /*subtype 50 */ {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_3},
499     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_1},
500     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_2},
501     {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_3}
502 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    
754     for (at = first_archetype; at != NULL; at = at->next)
755     {
756     if (QUERY_FLAG (&at->clone, FLAG_MONSTER) && (!QUERY_FLAG (&at->clone, FLAG_CHANGING) || QUERY_FLAG (&at->clone, FLAG_UNAGGRESSIVE)))
757     {
758 root 1.11 objectlink *mon = new objectlink;
759 root 1.5
760     mon->ob = &at->clone;
761     mon->next = first_mon_info;
762     first_mon_info = mon;
763     nrofmon++;
764     }
765     }
766 root 1.11
767 root 1.5 LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon);
768 elmex 1.1 }
769    
770 pippijn 1.16 /* init_readable() - initialise linked lists utilized by
771 elmex 1.1 * message functions in tailor_readable_ob()
772     *
773 pippijn 1.16 * This is the function called by the main routine to initialise
774 elmex 1.1 * all the readable information.
775     */
776 root 1.5 void
777 elmex 1.1 init_readable (void)
778     {
779 root 1.5 static int did_this;
780 elmex 1.1
781 root 1.5 if (did_this)
782     return;
783 root 1.11
784 root 1.5 did_this = 1;
785    
786 pippijn 1.14 LOG (llevDebug, "Initialising reading data...\n");
787 root 1.5 init_book_archive ();
788     init_mon_info ();
789     LOG (llevDebug, " Done\n");
790 elmex 1.1 }
791    
792     /*****************************************************************************
793     *
794     * This is the start of the administrative functions when creating
795     * new books (ie, updating title and the like)
796     *
797     *****************************************************************************/
798    
799     /* find_title() - Search the titlelist (based on msgtype) to see if
800     * book matches something already there. IF so, return that title.
801     */
802 root 1.5 static title *
803 elmex 1.1 find_title (const object *book, int msgtype)
804     {
805 root 1.5 title *t = NULL;
806     titlelist *tl = get_titlelist (msgtype);
807     int length = strlen (book->msg);
808     int index = strtoint (book->msg);
809    
810     if (msgtype < 0)
811     return (title *) NULL;
812    
813     if (tl)
814     t = tl->first_book;
815 root 1.6
816 root 1.5 while (t)
817     if (t->size == length && t->msg_index == index)
818     break;
819     else
820     t = t->next;
821 elmex 1.1
822     #ifdef ARCHIVE_DEBUG
823 root 1.5 if (t)
824     LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index);
825 elmex 1.1 #endif
826    
827 root 1.5 return t;
828 elmex 1.1 }
829    
830     /* new_text_name() - Only for objects of type BOOK. SPELLBOOK stuff is
831     * handled directly in change_book_name(). Names are based on text
832     * msgtype
833     * this sets book book->name based on msgtype given. What name
834     * is given is based on various criteria
835     */
836    
837 root 1.5 static void
838 elmex 1.1 new_text_name (object *book, int msgtype)
839     {
840 root 1.5 int nbr;
841     char name[MAX_BUF];
842 elmex 1.1
843 root 1.5 if (book->type != BOOK)
844     return;
845 elmex 1.1
846 root 1.5 switch (msgtype)
847     {
848 root 1.21 case 1: /*monster */
849     nbr = sizeof (mon_book_name) / sizeof (char *);
850     assign (name, mon_book_name[rndm (nbr)]);
851     break;
852     case 2: /*artifact */
853     nbr = sizeof (art_book_name) / sizeof (char *);
854     assign (name, art_book_name[rndm (nbr)]);
855     break;
856     case 3: /*spellpath */
857     nbr = sizeof (path_book_name) / sizeof (char *);
858     assign (name, path_book_name[rndm (nbr)]);
859     break;
860     case 4: /*alchemy */
861     nbr = sizeof (formula_book_name) / sizeof (char *);
862     assign (name, formula_book_name[rndm (nbr)]);
863     break;
864     case 5: /*gods */
865     nbr = sizeof (gods_book_name) / sizeof (char *);
866     assign (name, gods_book_name[rndm (nbr)]);
867     break;
868     case 6: /*msg file */
869     default:
870     if (book->weight > 2000)
871     { /* based on weight */
872     nbr = sizeof (heavy_book_name) / sizeof (char *);
873     assign (name, heavy_book_name[rndm (nbr)]);
874     }
875     else if (book->weight < 2001)
876     {
877     nbr = sizeof (light_book_name) / sizeof (char *);
878     assign (name, light_book_name[rndm (nbr)]);
879     }
880     break;
881 root 1.5 }
882 root 1.3
883 root 1.5 book->name = name;
884 elmex 1.1 }
885    
886     /* add_book_author()
887     * A lot like new_text_name above, but instead chooses an author
888     * and sets op->title to that value
889     */
890    
891 root 1.5 static void
892 elmex 1.1 add_author (object *op, int msgtype)
893     {
894 root 1.5 char title[MAX_BUF], name[MAX_BUF];
895     int nbr = sizeof (book_author) / sizeof (char *);
896 elmex 1.1
897 root 1.5 if (msgtype < 0 || strlen (op->msg) < 5)
898     return;
899 elmex 1.1
900 root 1.5 switch (msgtype)
901     {
902 root 1.21 case 1: /* monster */
903     nbr = sizeof (mon_author) / sizeof (char *);
904     assign (name, mon_author[rndm (nbr)]);
905     break;
906     case 2: /* artifacts */
907     nbr = sizeof (art_author) / sizeof (char *);
908     assign (name, art_author[rndm (nbr)]);
909     break;
910     case 3: /* spellpath */
911     nbr = sizeof (path_author) / sizeof (char *);
912     assign (name, path_author[rndm (nbr)]);
913     break;
914     case 4: /* alchemy */
915     nbr = sizeof (formula_author) / sizeof (char *);
916     assign (name, formula_author[rndm (nbr)]);
917     break;
918     case 5: /* gods */
919     nbr = sizeof (gods_author) / sizeof (char *);
920     assign (name, gods_author[rndm (nbr)]);
921     break;
922     case 6: /* msg file */
923     default:
924     assign (name, book_author[rndm (nbr)]);
925 root 1.5 }
926 elmex 1.1
927 root 1.5 sprintf (title, "of %s", name);
928     op->title = title;
929 elmex 1.1 }
930    
931     /* unique_book() - check to see if the book title/msg is unique. We
932     * go through the entire list of possibilities each time. If we find
933     * a match, then unique_book returns true (because inst unique).
934     */
935    
936 root 1.5 static int
937 elmex 1.1 unique_book (const object *book, int msgtype)
938     {
939 root 1.5 title *test;
940 elmex 1.1
941 root 1.5 if (!booklist)
942     return 1; /* No archival entries! Must be unique! */
943 elmex 1.1
944 root 1.5 /* Go through the booklist. If the author and name match, not unique so
945     * return 0.
946     */
947     for (test = get_titlelist (msgtype)->first_book; test; test = test->next)
948     {
949     if (!strcmp (test->name, book->name) && !strcmp (book->title, test->authour))
950     return 0;
951 elmex 1.1 }
952 root 1.5 return 1;
953 elmex 1.1 }
954    
955     /* add_book_to_list() */
956    
957 root 1.5 static void
958 elmex 1.1 add_book_to_list (const object *book, int msgtype)
959     {
960 root 1.5 titlelist *tl = get_titlelist (msgtype);
961     title *t;
962 elmex 1.1
963 root 1.5 if (!tl)
964     {
965     LOG (llevError, "add_book_to_list can't get booklist!\n");
966     return;
967     }
968 elmex 1.1
969 root 1.5 t = get_empty_book ();
970     t->name = book->name;
971     t->authour = book->title;
972     t->size = strlen (book->msg);
973     t->msg_index = strtoint (book->msg);
974     t->archname = book->arch->name;
975     t->level = book->level;
976    
977     t->next = tl->first_book;
978     tl->first_book = t;
979     tl->number++;
980 elmex 1.1
981 root 1.5 /* We have stuff we need to write now */
982     need_to_write_bookarchive = 1;
983 elmex 1.1
984     #ifdef ARCHIVE_DEBUG
985 root 1.5 LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
986 elmex 1.1 #endif
987    
988     }
989    
990    
991     /* change_book() - give a new, fancier name to generated
992     * objects of type BOOK and SPELLBOOK.
993     * Aug 96 I changed this so we will attempt to create consistent
994     * authour/title and message content for BOOKs. Also, we will
995     * alter books that match archive entries to the archival
996     * levels and architypes. -b.t.
997     */
998    
999     #define MAX_TITLE_CHECK 20
1000    
1001 root 1.5 void
1002 elmex 1.1 change_book (object *book, int msgtype)
1003     {
1004 root 1.5 int nbr = sizeof (book_descrpt) / sizeof (char *);
1005 elmex 1.1
1006 root 1.5 switch (book->type)
1007     {
1008     case BOOK:
1009 root 1.2 {
1010 root 1.5 titlelist *tl = get_titlelist (msgtype);
1011     title *t = NULL;
1012     int tries = 0;
1013    
1014     /* look to see if our msg already been archived. If so, alter
1015     * the book to match the archival text. If we fail to match,
1016     * then we archive the new title/name/msg combo if there is
1017     * room on the titlelist.
1018     */
1019 root 1.2
1020 root 1.5 if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype)))
1021     {
1022     object *tmpbook;
1023 root 1.2
1024 root 1.5 /* alter book properties */
1025     if ((tmpbook = get_archetype (t->archname)) != NULL)
1026     {
1027     tmpbook->msg = book->msg;
1028 root 1.13 tmpbook->copy_to (book);
1029     tmpbook->destroy ();
1030 root 1.5 }
1031 root 1.2
1032 root 1.5 book->title = t->authour;
1033     book->name = t->name;
1034     book->level = t->level;
1035     }
1036     /* Don't have any default title, so lets make up a new one */
1037     else
1038     {
1039     int numb, maxnames = max_titles[msgtype];
1040     const char *old_title;
1041     const char *old_name;
1042    
1043     old_title = book->title;
1044     old_name = book->name;
1045    
1046     /* some pre-generated books have title already set (from
1047     * maps), also don't bother looking for unique title if
1048     * we already used up all the available names! */
1049 root 1.2
1050 root 1.5 if (!tl)
1051     {
1052     LOG (llevError, "change_book_name(): can't find title list\n");
1053     numb = 0;
1054     }
1055     else
1056     numb = tl->number;
1057 elmex 1.1
1058 root 1.5 if (numb == maxnames)
1059     {
1060 elmex 1.1 #ifdef ARCHIVE_DEBUG
1061 root 1.5 LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1062 elmex 1.1 #endif
1063 root 1.5 break;
1064     }
1065     /* shouldnt change map-maker books */
1066     else if (!book->title)
1067     do
1068     {
1069     /* random book name */
1070     new_text_name (book, msgtype);
1071     add_author (book, msgtype); /* random author */
1072     tries++;
1073     }
1074     while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK);
1075    
1076     /* Now deal with 2 cases.
1077     * 1)If no space for a new title exists lets just restore
1078     * the old book properties. Remember, if the book had
1079     * matchd an older entry on the titlelist, we shouldnt
1080     * have called this routine in the first place!
1081     * 2) If we got a unique title, we need to add it to
1082     * the list.
1083     */
1084 elmex 1.1
1085 root 1.5 if (tries == MAX_TITLE_CHECK || numb == maxnames)
1086     { /* got to check maxnames again */
1087 elmex 1.1 #ifdef ARCHIVE_DEBUG
1088 root 1.5 LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1089 elmex 1.1 #endif
1090 root 1.5 /* restore old book properties here */
1091     book->title = old_title;
1092    
1093     if (RANDOM () % 4)
1094     {
1095     /* Lets give the book a description to individualize it some */
1096     char new_name[MAX_BUF];
1097    
1098 root 1.19 snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[rndm (nbr)], old_name);
1099 root 1.2
1100 root 1.5 book->name = new_name;
1101     }
1102     else
1103     {
1104     book->name = old_name;
1105 root 1.2 }
1106 root 1.5 }
1107     else if (book->title && strlen (book->msg) > 5)
1108     { /* archive if long msg texts */
1109     add_book_to_list (book, msgtype);
1110     }
1111     }
1112     break;
1113 root 1.2 }
1114 elmex 1.1
1115 root 1.5 default:
1116 root 1.2 LOG (llevError, "change_book_name() called w/ illegal obj type.\n");
1117     return;
1118 root 1.5 }
1119 elmex 1.1 }
1120    
1121     /*****************************************************************************
1122     *
1123     * This is the start of the area that generates the actual contents
1124     * of the book.
1125     *
1126     *****************************************************************************/
1127    
1128     /*****************************************************************************
1129     * Monster msg generation code.
1130     ****************************************************************************/
1131    
1132     /* get_random_mon() - returns a random monster slected from linked
1133     * list of all monsters in the current game. If level is non-zero,
1134     * then only monsters greater than that level will be returned.
1135     * Changed 971225 to be greater than equal to level passed. Also
1136     * made choosing by level more random.
1137     */
1138    
1139     object *
1140     get_random_mon (int level)
1141     {
1142 root 1.5 objectlink *mon = first_mon_info;
1143     int i = 0, monnr;
1144    
1145     /* safety check. Problem w/ init_mon_info list? */
1146     if (!nrofmon || !mon)
1147     return (object *) NULL;
1148    
1149     if (!level)
1150     {
1151     /* lets get a random monster from the mon_info linked list */
1152     monnr = RANDOM () % nrofmon;
1153 elmex 1.1
1154 root 1.5 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1155     if (i++ == monnr)
1156     break;
1157    
1158     if (!mon)
1159     {
1160     LOG (llevError, "get_random_mon: Didn't find a monster when we should have\n");
1161 root 1.2 return NULL;
1162 root 1.5 }
1163     return mon->ob;
1164     }
1165 elmex 1.1
1166 root 1.5 /* Case where we are searching by level. Redone 971225 to be clearer
1167     * and more random. Before, it looks like it took a random monster from
1168     * the list, and then returned the first monster after that which was
1169     * appropriate level. This wasn't very random because if you had a
1170     * bunch of low level monsters and then a high level one, if the random
1171     * determine took one of the low level ones, it would just forward to the
1172     * high level one and return that. Thus, monsters that immediatly followed
1173     * a bunch of low level monsters would be more heavily returned. It also
1174     * means some of the dragons would be poorly represented, since they
1175     * are a group of high level monsters all around each other.
1176     */
1177    
1178     /* First count number of monsters meeting level criteria */
1179     for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1180     if (mon->ob->level >= level)
1181     i++;
1182    
1183     if (i == 0)
1184     {
1185     LOG (llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1186     return NULL;
1187     }
1188    
1189     monnr = RANDOM () % i;
1190     for (mon = first_mon_info; mon; mon = mon->next)
1191     if (mon->ob->level >= level && monnr-- == 0)
1192     return mon->ob;
1193    
1194     if (!mon)
1195     {
1196     LOG (llevError, "get_random_mon(): didn't find a monster when we should have\n");
1197     return NULL;
1198     }
1199     return NULL; /* Should be unreached, by keeps warnings down */
1200 elmex 1.1 }
1201    
1202     /*
1203     * Returns a description of the monster. This really needs to be
1204     * redone, as describe_item really gives a pretty internal description.
1205     */
1206    
1207 root 1.5 char *
1208 elmex 1.1 mon_desc (const object *mon)
1209     {
1210 root 1.5 static char retbuf[HUGE_BUF];
1211 elmex 1.1
1212 root 1.5 sprintf (retbuf, " *** %s ***\n", &mon->name);
1213     strcat (retbuf, describe_item (mon, NULL));
1214 elmex 1.1
1215 root 1.5 return retbuf;
1216 elmex 1.1 }
1217    
1218    
1219     /* This function returns the next monsters after 'tmp'. If no match is
1220     * found, it returns NULL (changed 0.94.3 to do this, since the
1221     * calling function (mon_info_msg) seems to expect that.
1222     */
1223    
1224     object *
1225     get_next_mon (object *tmp)
1226     {
1227 root 1.5 objectlink *mon;
1228 elmex 1.1
1229 root 1.5 for (mon = first_mon_info; mon; mon = mon->next)
1230     if (mon->ob == tmp)
1231     break;
1232    
1233     /* didn't find a match */
1234     if (!mon)
1235     return NULL;
1236     if (mon->next)
1237     return mon->next->ob;
1238     else
1239     return first_mon_info->ob;
1240 elmex 1.1
1241     }
1242    
1243    
1244    
1245     /* mon_info_msg() - generate a message detailing the properties
1246     * of a randomly selected monster.
1247     */
1248    
1249 root 1.5 char *
1250 elmex 1.1 mon_info_msg (int level, int booksize)
1251     {
1252 root 1.5 static char retbuf[BOOK_BUF];
1253     char tmpbuf[HUGE_BUF];
1254     object *tmp;
1255    
1256     /*preamble */
1257     strcpy (retbuf, "This beastiary contains:");
1258    
1259     /* lets print info on as many monsters as will fit in our
1260     * document.
1261     * 8-96 Had to change this a bit, otherwise there would
1262     * have been an impossibly large number of combinations
1263     * of text! (and flood out the available number of titles
1264     * in the archive in a snap!) -b.t.
1265     */
1266     tmp = get_random_mon (level * 3);
1267     while (tmp)
1268     {
1269     /* monster description */
1270     sprintf (tmpbuf, "\n---\n%s", mon_desc (tmp));
1271    
1272     if (!book_overflow (retbuf, tmpbuf, booksize))
1273     strcat (retbuf, tmpbuf);
1274     else
1275     break;
1276 elmex 1.1
1277 root 1.5 /* Note that the value this returns is not based on level */
1278     tmp = get_next_mon (tmp);
1279 elmex 1.1 }
1280    
1281     #ifdef BOOK_MSG_DEBUG
1282 root 1.5 LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf));
1283     fprintf (logfile, " MADE THIS:\n%s\n", retbuf);
1284 elmex 1.1 #endif
1285    
1286 root 1.5 return retbuf;
1287 elmex 1.1 }
1288    
1289    
1290     /*****************************************************************************
1291     * Artifact msg generation code.
1292     ****************************************************************************/
1293    
1294     /* artifact_msg() - generate a message detailing the properties
1295     * of 1-6 artifacts drawn sequentially from the artifact list.
1296     */
1297 root 1.22 const char *
1298 elmex 1.1 artifact_msg (int level, int booksize)
1299     {
1300 root 1.5 artifactlist *al = NULL;
1301     artifact *art;
1302     int chance, i, type, index;
1303     int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1;
1304 root 1.22 const char *ch;
1305     char name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF];
1306 root 1.5 static char retbuf[BOOK_BUF];
1307     object *tmp = NULL;
1308    
1309     /* values greater than 5 create msg buffers that are too big! */
1310     if (book_entries > 5)
1311     book_entries = 5;
1312    
1313     /* lets determine what kind of artifact type randomly.
1314     * Right now legal artifacts only come from those listed
1315     * in art_name_array. Also, we check to be sure an artifactlist
1316     * for that type exists!
1317     */
1318     i = 0;
1319     do
1320     {
1321     index = RANDOM () % (sizeof (art_name_array) / sizeof (arttypename));
1322     type = art_name_array[index].type;
1323     al = find_artifactlist (type);
1324     i++;
1325     }
1326     while ((al == NULL) && (i < 10));
1327    
1328     if (i == 10) /* Unable to find a message */
1329 root 1.22 return "None";
1330 elmex 1.1
1331 root 1.5 /* There is no reason to start on the artifact list at the begining. Lets
1332     * take our starting position randomly... */
1333     art = al->items;
1334     for (i = RANDOM () % level + RANDOM () % 2 + 1; i > 0; i--)
1335     {
1336     if (art == NULL)
1337     art = al->items; /* hmm, out of stuff, loop back around */
1338     art = art->next;
1339     }
1340    
1341     /* the base 'generic' name for our artifact */
1342 root 1.21 assign (name, art_name_array[index].name);
1343 root 1.5
1344     /* Ok, lets print out the contents */
1345     sprintf (retbuf, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1346    
1347     /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1348     * as long as we have space up to the allowed max # (book_entires)
1349     */
1350     while (book_entries > 0)
1351     {
1352    
1353     if (art == NULL)
1354     art = al->items;
1355 elmex 1.1
1356 root 1.5 /* separator of items */
1357     strcpy (buf, "--- \n");
1358    
1359     /* Name */
1360     if (art->allowed != NULL && strcmp (art->allowed->name, "All"))
1361     {
1362     linked_char *temp, *next = art->allowed;
1363    
1364     do
1365 root 1.2 {
1366 root 1.5 temp = next;
1367     next = next->next;
1368 root 1.2 }
1369 root 1.5 while (next && !RANDOM () % 2);
1370     sprintf (buf, "%s A %s of %s", buf, &temp->name, &art->item->name);
1371     }
1372     else /* default name is used */
1373     sprintf (buf, "%s The %s of %s", buf, name, &art->item->name);
1374 root 1.2
1375 root 1.5 /* chance of finding */
1376     chance = (int) (100 * ((float) art->chance / al->total_chance));
1377     if (chance >= 20)
1378     sprintf (sbuf, "an uncommon");
1379     else if (chance >= 10)
1380     sprintf (sbuf, "an unusual");
1381     else if (chance >= 5)
1382     sprintf (sbuf, "a rare");
1383     else
1384     sprintf (sbuf, "a very rare");
1385     sprintf (buf, "%s is %s\n", buf, sbuf);
1386    
1387     /* value of artifact */
1388     sprintf (buf, "%s item with a value that is %d times normal.\n", buf, art->item->value);
1389    
1390     /* include the message about the artifact, if exists, and book
1391     * level is kinda high */
1392     if (art->item->msg && (RANDOM () % 4 + 1) < level && !((strlen (art->item->msg) + strlen (buf)) > BOOK_BUF))
1393     strcat (buf, art->item->msg);
1394    
1395     /* properties of the artifact */
1396 root 1.13 tmp = object::create ();
1397 root 1.5 add_abilities (tmp, art->item);
1398     tmp->type = type;
1399     SET_FLAG (tmp, FLAG_IDENTIFIED);
1400     if ((ch = describe_item (tmp, NULL)) != NULL && strlen (ch) > 1)
1401     sprintf (buf, "%s Properties of this artifact include: \n %s \n", buf, ch);
1402 root 1.13 tmp->destroy ();
1403 root 1.5 /* add the buf if it will fit */
1404     if (!book_overflow (retbuf, buf, booksize))
1405     strcat (retbuf, buf);
1406     else
1407     break;
1408 root 1.2
1409 root 1.5 art = art->next;
1410     book_entries--;
1411     }
1412 elmex 1.1
1413     #ifdef BOOK_MSG_DEBUG
1414 root 1.5 LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf));
1415     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1416 elmex 1.1 #endif
1417 root 1.5 return retbuf;
1418 elmex 1.1 }
1419    
1420     /*****************************************************************************
1421     * Spellpath message generation
1422     *****************************************************************************/
1423    
1424     /* spellpath_msg() - generate a message detailing the member
1425     * incantations/prayers (and some of their properties) belonging to
1426     * a given spellpath.
1427     */
1428    
1429 root 1.5 char *
1430 elmex 1.1 spellpath_msg (int level, int booksize)
1431     {
1432 root 1.5 static char retbuf[BOOK_BUF];
1433     char tmpbuf[BOOK_BUF];
1434     int path = RANDOM () % NRSPELLPATHS, prayers = RANDOM () % 2;
1435     int did_first_sp = 0;
1436     uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path];
1437     archetype *at;
1438    
1439     /* Preamble */
1440     sprintf (retbuf, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
1441    
1442     if (path == -1)
1443     strcat (retbuf, "having no known spell path.\n");
1444     else
1445     sprintf (retbuf, "%sbelonging to the path of %s:\n", retbuf, spellpathnames[path]);
1446    
1447     for (at = first_archetype; at != NULL; at = at->next)
1448     {
1449     /* Determine if this is an appropriate spell. Must
1450     * be of matching path, must be of appropriate type (prayer
1451     * or not), and must be within the valid level range.
1452     */
1453     if (at->clone.type == SPELL && at->clone.path_attuned & pnum &&
1454     ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers)) && (at->clone.level < (level * 8)))
1455     {
1456 root 1.21 assign (tmpbuf, at->clone.name);
1457 elmex 1.1
1458 root 1.5 if (book_overflow (retbuf, tmpbuf, booksize))
1459     break;
1460     else
1461     {
1462     if (did_first_sp)
1463     strcat (retbuf, ",\n");
1464     did_first_sp = 1;
1465     strcat (retbuf, tmpbuf);
1466 root 1.2 }
1467 root 1.5 }
1468 elmex 1.1 }
1469 root 1.5 /* Geez, no spells were generated. */
1470     if (!did_first_sp)
1471     {
1472     if (RANDOM () % 4) /* usually, lets make a recursive call... */
1473     spellpath_msg (level, booksize);
1474     else /* give up, cause knowing no spells exist for path is info too. */
1475     strcat (retbuf, "\n - no known spells exist -\n");
1476 elmex 1.1 }
1477 root 1.5 else
1478     {
1479     strcat (retbuf, "\n");
1480 elmex 1.1 }
1481 root 1.5 return retbuf;
1482 elmex 1.1 }
1483    
1484     /* formula_msg() - generate a message detailing the properties
1485     * of a randomly selected alchemical formula.
1486     */
1487 root 1.5 void
1488     make_formula_book (object *book, int level)
1489     {
1490     char retbuf[BOOK_BUF], title[MAX_BUF];
1491     recipelist *fl;
1492     recipe *formula = NULL;
1493     int chance;
1494    
1495     /* the higher the book level, the more complex (ie number of
1496     * ingredients) the formula can be.
1497     */
1498     fl = get_formulalist (((RANDOM () % level) / 3) + 1);
1499    
1500     if (!fl)
1501     fl = get_formulalist (1); /* safety */
1502    
1503     if (fl->total_chance == 0)
1504     {
1505     book->msg = "<indecipherable text>\n";
1506     new_text_name (book, 4);
1507     add_author (book, 4);
1508     return;
1509     }
1510    
1511     /* get a random formula, weighted by its bookchance */
1512     chance = RANDOM () % fl->total_chance;
1513     for (formula = fl->items; formula != NULL; formula = formula->next)
1514     {
1515     chance -= formula->chance;
1516     if (chance <= 0)
1517     break;
1518     }
1519    
1520     if (!formula || formula->arch_names <= 0)
1521     {
1522     book->msg = "<indecipherable text>\n";
1523     new_text_name (book, 4);
1524     add_author (book, 4);
1525    
1526 elmex 1.1 }
1527 root 1.5 else
1528     {
1529     /* looks like a formula was found. Base the amount
1530     * of information on the booklevel and the spellevel
1531     * of the formula. */
1532    
1533     const char *op_name = formula->arch_name[RANDOM () % formula->arch_names];
1534     archetype *at;
1535    
1536     /* preamble */
1537     sprintf (retbuf, "Herein is described a project using %s: \n", formula->skill ? &formula->skill : "an unknown skill");
1538    
1539 root 1.8 if ((at = archetype::find (op_name)) != (archetype *) NULL)
1540 root 1.5 op_name = at->clone.name;
1541     else
1542     LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1543 elmex 1.1
1544 root 1.5 /* item name */
1545     if (strcmp (formula->title, "NONE"))
1546     {
1547     sprintf (retbuf, "%sThe %s of %s", retbuf, op_name, &formula->title);
1548     /* This results in things like pile of philo. sulfur.
1549     * while philo. sulfur may look better, without this,
1550     * you get things like 'the wise' because its missing the
1551     * water of section.
1552     */
1553     sprintf (title, "%s: %s of %s",
1554     formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title);
1555 root 1.2 }
1556 root 1.5 else
1557 root 1.2 {
1558 root 1.5 sprintf (retbuf, "%sThe %s", retbuf, op_name);
1559     sprintf (title, "%s: %s", formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name);
1560     if (at->clone.title)
1561     {
1562     strcat (retbuf, " ");
1563     strcat (retbuf, at->clone.title);
1564     strcat (title, " ");
1565     strcat (title, at->clone.title);
1566 root 1.2 }
1567     }
1568 root 1.5 /* Lets name the book something meaningful ! */
1569     book->name = title;
1570     book->title = NULL;
1571 root 1.2
1572 root 1.5 /* ingredients to make it */
1573     if (formula->ingred != NULL)
1574 root 1.2 {
1575 root 1.5 linked_char *next;
1576     archetype *at;
1577 root 1.2
1578 root 1.8 at = archetype::find (formula->cauldron);
1579 root 1.2
1580 root 1.5 sprintf (retbuf + strlen (retbuf),
1581     " may be made at %s using the following ingredients:\n", at ? query_name (&at->clone) : "an unknown place");
1582 root 1.2
1583 root 1.5 for (next = formula->ingred; next != NULL; next = next->next)
1584 root 1.2 {
1585 root 1.5 strcat (retbuf, next->name);
1586     strcat (retbuf, "\n");
1587 root 1.2 }
1588     }
1589 root 1.5 else
1590     LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title);
1591     if (retbuf[strlen (retbuf) - 1] != '\n')
1592     strcat (retbuf, "\n");
1593 root 1.3
1594 root 1.5 book->msg = retbuf;
1595 elmex 1.1 }
1596     }
1597    
1598     /* god_info_msg() - generate a message detailing the properties
1599     * of a random god. Used by the book hack. b.t.
1600     */
1601 root 1.5 const char *
1602 elmex 1.1 god_info_msg (int level, int booksize)
1603     {
1604 root 1.5 static char retbuf[BOOK_BUF];
1605     const char *name = NULL;
1606     char buf[BOOK_BUF];
1607     int i;
1608     size_t introlen;
1609     object *god = pntr_to_god_obj (get_rand_god ());
1610    
1611     if (!god)
1612     return (char *) NULL; /* oops, problems... */
1613     name = god->name;
1614    
1615     /* preamble.. */
1616     sprintf (retbuf, "This document contains knowledge concerning\n");
1617     sprintf (retbuf, "%sthe diety %s", retbuf, name);
1618    
1619     /* Always have as default information the god's descriptive terms. */
1620     if (nstrtok (god->msg, ",") > 0)
1621     {
1622     strcat (retbuf, ", known as");
1623     strcat (retbuf, strtoktolin (god->msg, ","));
1624     }
1625     else
1626     strcat (retbuf, "...");
1627    
1628     strcat (retbuf, "\n ---\n");
1629     introlen = strlen (retbuf); /* so we will know if no new info is added later */
1630 elmex 1.1
1631 root 1.5 /* Information about the god is random, and based on the level of the
1632     * 'book'. Probably there is a more intellegent way to implement
1633     * this ...
1634     */
1635    
1636     while (level > 0)
1637     {
1638     sprintf (buf, " ");
1639     if (level == 2 && RANDOM () % 2)
1640     { /* enemy god */
1641     const char *enemy = god->title;
1642 elmex 1.1
1643 root 1.5 if (enemy)
1644     sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy);
1645     }
1646 root 1.22
1647 root 1.5 if (level == 3 && RANDOM () % 2)
1648     { /* enemy race, what the god's holy word effects */
1649     const char *enemy = god->slaying;
1650    
1651     if (enemy && !(god->path_denied & PATH_TURNING))
1652     if ((i = nstrtok (enemy, ",")) > 0)
1653     {
1654     char tmpbuf[MAX_BUF];
1655    
1656     sprintf (buf, "The holy words of %s have the power to\n", name);
1657     strcat (buf, "slay creatures belonging to the ");
1658     if (i > 1)
1659     sprintf (tmpbuf, "following \n races:%s", strtoktolin (enemy, ","));
1660     else
1661     sprintf (tmpbuf, "race of%s", strtoktolin (enemy, ","));
1662     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1663     }
1664     }
1665 root 1.22
1666 root 1.5 if (level == 4 && RANDOM () % 2)
1667     { /* Priest of god gets these protect,vulnerable... */
1668 root 1.22 char tmpbuf[MAX_BUF];
1669 root 1.5
1670 root 1.22 if (const char *cp = describe_resistance (god, 1))
1671 root 1.5 { /* This god does have protections */
1672     sprintf (tmpbuf, "%s has a potent aura which is extended\n", name);
1673     strcat (tmpbuf, "faithful priests. The effects of this aura include:\n");
1674     strcat (tmpbuf, cp);
1675     strcat (buf, tmpbuf);
1676     strcat (buf, "\n ---\n");
1677     }
1678     else
1679     sprintf (buf, " ");
1680     }
1681 root 1.22
1682 root 1.5 if (level == 5 && RANDOM () % 2)
1683     { /* aligned race, summoning */
1684     const char *race = god->race; /* aligned race */
1685    
1686     if (race && !(god->path_denied & PATH_SUMMON))
1687     if ((i = nstrtok (race, ",")) > 0)
1688     {
1689     char tmpbuf[MAX_BUF];
1690    
1691     sprintf (buf, "Creatures sacred to %s include the \n", name);
1692     if (i > 1)
1693     sprintf (tmpbuf, "following \n races:%s", strtoktolin (race, ","));
1694     else
1695     sprintf (tmpbuf, "race of%s", strtoktolin (race, ","));
1696     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1697     }
1698     }
1699 root 1.22
1700 root 1.5 if (level == 6 && RANDOM () % 2)
1701     { /* blessing,curse properties of the god */
1702 root 1.22 char tmpbuf[MAX_BUF];
1703 root 1.5
1704 root 1.22 if (const char *cp = describe_resistance (god, 1))
1705 root 1.5 { /* This god does have protections */
1706     sprintf (tmpbuf, "\nThe priests of %s are known to be able to \n", name);
1707     strcat (tmpbuf, "bestow a blessing which makes the recipient\n");
1708     strcat (tmpbuf, cp);
1709     strcat (buf, tmpbuf);
1710     strcat (buf, "\n ---\n");
1711 root 1.2 }
1712 root 1.5 else
1713     sprintf (buf, " ");
1714    
1715     }
1716 root 1.22
1717 root 1.5 if (level == 8 && RANDOM () % 2)
1718     { /* immunity, holy possession */
1719     int has_effect = 0, tmpvar;
1720     char tmpbuf[MAX_BUF];
1721    
1722     sprintf (tmpbuf, "\n");
1723     sprintf (tmpbuf, "The priests of %s are known to make cast a mighty \n", name);
1724    
1725     strcat (tmpbuf, "prayer of possession which gives the recipient\n");
1726    
1727     for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
1728     {
1729     if (god->resist[tmpvar] == 100)
1730     {
1731     has_effect = 1;
1732     sprintf (tmpbuf + strlen (tmpbuf), "Immunity to %s", attacktype_desc[tmpvar]);
1733 root 1.2 }
1734     }
1735 root 1.22
1736 root 1.5 if (has_effect)
1737     {
1738     strcat (buf, tmpbuf);
1739     strcat (buf, "\n ---\n");
1740     }
1741     else
1742     sprintf (buf, " ");
1743     }
1744 root 1.22
1745 root 1.5 if (level == 12 && RANDOM () % 2)
1746     { /* spell paths */
1747     int has_effect = 0, tmpvar;
1748     char tmpbuf[MAX_BUF];
1749    
1750     sprintf (tmpbuf, "\n");
1751     sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name);
1752     strcat (tmpbuf, "are mystically transformed. Effects of this include:\n");
1753 root 1.22
1754 root 1.5 if ((tmpvar = god->path_attuned))
1755     {
1756     has_effect = 1;
1757     DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned");
1758 root 1.2 }
1759 root 1.22
1760 root 1.5 if ((tmpvar = god->path_repelled))
1761     {
1762     has_effect = 1;
1763     DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled");
1764 root 1.2 }
1765 root 1.22
1766 root 1.5 if ((tmpvar = god->path_denied))
1767     {
1768     has_effect = 1;
1769     DESCRIBE_PATH (tmpbuf, tmpvar, "Denied");
1770 root 1.2 }
1771 root 1.22
1772 root 1.5 if (has_effect)
1773     {
1774     strcat (buf, tmpbuf);
1775     strcat (buf, "\n ---\n");
1776 root 1.2 }
1777 root 1.5 else
1778     sprintf (buf, " ");
1779     }
1780 root 1.2
1781 root 1.5 /* check to be sure new buffer size dont exceed either
1782     * the maximum buffer size, or the 'natural' size of the
1783     * book...
1784     */
1785     if (book_overflow (retbuf, buf, booksize))
1786     break;
1787     else if (strlen (buf) > 1)
1788     strcat (retbuf, buf);
1789 root 1.22
1790 root 1.5 level--;
1791     }
1792 root 1.22
1793 root 1.5 if (strlen (retbuf) == introlen)
1794     { /* we got no information beyond the preamble! */
1795     strcat (retbuf, " [Unfortunately the rest of the information is\n");
1796     strcat (retbuf, " hopelessly garbled!]\n ---\n");
1797     }
1798 elmex 1.1 #ifdef BOOK_MSG_DEBUG
1799 root 1.5 LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf));
1800     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1801 elmex 1.1 #endif
1802 root 1.5 return retbuf;
1803 elmex 1.1 }
1804    
1805     /* tailor_readable_ob()- The main routine. This chooses a random
1806     * message to put in given readable object (type==BOOK) which will
1807     * be referred hereafter as a 'book'. We use the book level to de-
1808     * termine the value of the information we will insert. Higher
1809     * values mean the book will (generally) have better/more info.
1810     * See individual cases as to how this will be utilized.
1811     * "Book" name/content length are based on the weight of the
1812     * document. If the value of msg_type is negative, we will randomly
1813     * choose the kind of message to generate.
1814     * -b.t. thomas@astro.psu.edu
1815     *
1816     * book is the object we are creating into.
1817     * If msg_type is a positive value, we use that to determine the
1818     * message type - otherwise a random value is used.
1819     *
1820     */
1821 root 1.5 void
1822 elmex 1.1 tailor_readable_ob (object *book, int msg_type)
1823     {
1824 root 1.5 char msgbuf[BOOK_BUF];
1825     int level = book->level ? (RANDOM () % book->level) + 1 : 1;
1826     int book_buf_size;
1827    
1828     /* safety */
1829     if (book->type != BOOK)
1830     return;
1831    
1832     if (level <= 0)
1833     return; /* if no level no point in doing any more... */
1834    
1835     /* Max text length this book can have. */
1836     book_buf_size = BOOKSIZE (book);
1837    
1838     /* &&& The message switch &&& */
1839     /* Below all of the possible types of messages in the "book"s.
1840     */
1841     /*
1842     * IF you add a new type of book msg, you will have to do several things.
1843     * 1) make sure there is an entry in the msg switch below!
1844     * 2) make sure there is an entry in max_titles[] array.
1845     * 3) make sure there are entries for your case in new_text_title()
1846     * and add_authour().
1847     * 4) you may want separate authour/book name arrays in read.h
1848     */
1849    
1850     msg_type = msg_type > 0 ? msg_type : (RANDOM () % 6);
1851     switch (msg_type)
1852     {
1853 root 1.24 case 1: /* monster attrib */
1854     strcpy (msgbuf, mon_info_msg (level, book_buf_size));
1855     break;
1856     case 2: /* artifact attrib */
1857     strcpy (msgbuf, artifact_msg (level, book_buf_size));
1858     break;
1859     case 3: /* grouping incantations/prayers by path */
1860     strcpy (msgbuf, spellpath_msg (level, book_buf_size));
1861     break;
1862     case 4: /* describe an alchemy formula */
1863     make_formula_book (book, level);
1864     /* make_formula_book already gives title */
1865     return;
1866     break;
1867     case 5: /* bits of information about a god */
1868     strcpy (msgbuf, god_info_msg (level, book_buf_size));
1869     break;
1870     case 0: /* use info list in lib/ */
1871     default:
1872     cfperl_make_book (book, level);
1873     return;
1874 root 1.5 }
1875 elmex 1.1
1876 root 1.5 strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
1877 root 1.10
1878 root 1.5 if (strlen (msgbuf) > 1)
1879     {
1880     book->msg = msgbuf;
1881     /* lets give the "book" a new name, which may be a compound word */
1882     change_book (book, msg_type);
1883     }
1884 elmex 1.1
1885     }
1886    
1887    
1888     /*****************************************************************************
1889     *
1890     * Cleanup routine for readble stuff.
1891     *
1892     *****************************************************************************/
1893    
1894 root 1.5 void
1895 elmex 1.1 free_all_readable (void)
1896     {
1897 root 1.5 titlelist *tlist, *tnext;
1898     title *title1, *titlenext;
1899     linked_char *lmsg, *nextmsg;
1900     objectlink *monlink, *nextmon;
1901    
1902     LOG (llevDebug, "freeing all book information\n");
1903    
1904     for (tlist = booklist; tlist != NULL; tlist = tnext)
1905     {
1906     tnext = tlist->next;
1907    
1908     for (title1 = tlist->first_book; title1; title1 = titlenext)
1909     {
1910     titlenext = title1->next;
1911     delete title1;
1912     }
1913    
1914     delete tlist;
1915     }
1916 root 1.10
1917 root 1.5 for (lmsg = first_msg; lmsg; lmsg = nextmsg)
1918     {
1919     nextmsg = lmsg->next;
1920     delete lmsg;
1921     }
1922 root 1.10
1923 root 1.5 for (monlink = first_mon_info; monlink; monlink = nextmon)
1924     {
1925     nextmon = monlink->next;
1926 root 1.11 delete monlink;
1927 root 1.5 }
1928 elmex 1.1 }
1929    
1930    
1931     /*****************************************************************************
1932     *
1933     * Writeback routine for updating the bookarchive.
1934     *
1935     ****************************************************************************/
1936    
1937     /* write_book_archive() - write out the updated book archive */
1938    
1939 root 1.5 void
1940 elmex 1.1 write_book_archive (void)
1941     {
1942 root 1.5 FILE *fp;
1943     int index = 0;
1944     char fname[MAX_BUF];
1945     title *book = NULL;
1946     titlelist *bl = get_titlelist (0);
1947    
1948     /* If nothing changed, don't write anything */
1949     if (!need_to_write_bookarchive)
1950     return;
1951     need_to_write_bookarchive = 0;
1952    
1953     sprintf (fname, "%s/bookarch", settings.localdir);
1954     LOG (llevDebug, "Updating book archive: %s...\n", fname);
1955    
1956     if ((fp = fopen (fname, "w")) == NULL)
1957     {
1958     LOG (llevDebug, "Can't open book archive file %s\n", fname);
1959     }
1960     else
1961     {
1962     while (bl)
1963     {
1964     for (book = bl->first_book; book; book = book->next)
1965     if (book && book->authour)
1966     {
1967     fprintf (fp, "title %s\n", &book->name);
1968     fprintf (fp, "authour %s\n", &book->authour);
1969     fprintf (fp, "arch %s\n", &book->archname);
1970     fprintf (fp, "level %d\n", book->level);
1971     fprintf (fp, "type %d\n", index);
1972     fprintf (fp, "size %d\n", book->size);
1973     fprintf (fp, "index %d\n", book->msg_index);
1974     fprintf (fp, "end\n");
1975     }
1976     bl = bl->next;
1977     index++;
1978     }
1979     fclose (fp);
1980     chmod (fname, SAVE_MODE);
1981     }
1982     }
1983     readable_message_type *
1984     get_readable_message_type (object *readable)
1985     {
1986     uint8 subtype = readable->subtype;
1987    
1988     if (subtype > last_readable_subtype)
1989     return &(readable_message_types[0]);
1990     return &(readable_message_types[subtype]);
1991 elmex 1.1 }