ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/readable.C
Revision: 1.27
Committed: Mon Jun 4 13:04:00 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +12 -13 lines
Log Message:
- archetype is now a subclass of object.
- store archetypes in an object_vector.
- use a different startegy for archetype loading
  (reloading is MOST CERTAINLY broken).

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 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     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 title *test;
939 elmex 1.1
940 root 1.5 if (!booklist)
941     return 1; /* No archival entries! Must be unique! */
942 elmex 1.1
943 root 1.5 /* Go through the booklist. If the author and name match, not unique so
944     * return 0.
945     */
946     for (test = get_titlelist (msgtype)->first_book; test; test = test->next)
947     {
948     if (!strcmp (test->name, book->name) && !strcmp (book->title, test->authour))
949     return 0;
950 elmex 1.1 }
951 root 1.5 return 1;
952 elmex 1.1 }
953    
954     /* add_book_to_list() */
955    
956 root 1.5 static void
957 elmex 1.1 add_book_to_list (const object *book, int msgtype)
958     {
959 root 1.5 titlelist *tl = get_titlelist (msgtype);
960     title *t;
961 elmex 1.1
962 root 1.5 if (!tl)
963     {
964     LOG (llevError, "add_book_to_list can't get booklist!\n");
965     return;
966     }
967 elmex 1.1
968 root 1.5 t = get_empty_book ();
969     t->name = book->name;
970     t->authour = book->title;
971     t->size = strlen (book->msg);
972     t->msg_index = strtoint (book->msg);
973 root 1.26 t->archname = book->arch->archname;
974 root 1.5 t->level = book->level;
975    
976     t->next = tl->first_book;
977     tl->first_book = t;
978     tl->number++;
979 elmex 1.1
980 root 1.5 /* We have stuff we need to write now */
981     need_to_write_bookarchive = 1;
982 elmex 1.1
983     #ifdef ARCHIVE_DEBUG
984 root 1.5 LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype);
985 elmex 1.1 #endif
986    
987     }
988    
989    
990     /* change_book() - give a new, fancier name to generated
991     * objects of type BOOK and SPELLBOOK.
992     * Aug 96 I changed this so we will attempt to create consistent
993     * authour/title and message content for BOOKs. Also, we will
994     * alter books that match archive entries to the archival
995     * levels and architypes. -b.t.
996     */
997    
998     #define MAX_TITLE_CHECK 20
999    
1000 root 1.5 void
1001 elmex 1.1 change_book (object *book, int msgtype)
1002     {
1003 root 1.5 int nbr = sizeof (book_descrpt) / sizeof (char *);
1004 elmex 1.1
1005 root 1.5 switch (book->type)
1006     {
1007     case BOOK:
1008 root 1.2 {
1009 root 1.5 titlelist *tl = get_titlelist (msgtype);
1010     title *t = NULL;
1011     int tries = 0;
1012    
1013     /* look to see if our msg already been archived. If so, alter
1014     * the book to match the archival text. If we fail to match,
1015     * then we archive the new title/name/msg combo if there is
1016     * room on the titlelist.
1017     */
1018 root 1.2
1019 root 1.5 if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype)))
1020     {
1021     object *tmpbook;
1022 root 1.2
1023 root 1.5 /* alter book properties */
1024     if ((tmpbook = get_archetype (t->archname)) != NULL)
1025     {
1026     tmpbook->msg = book->msg;
1027 root 1.13 tmpbook->copy_to (book);
1028     tmpbook->destroy ();
1029 root 1.5 }
1030 root 1.2
1031 root 1.5 book->title = t->authour;
1032     book->name = t->name;
1033     book->level = t->level;
1034     }
1035     /* Don't have any default title, so lets make up a new one */
1036     else
1037     {
1038     int numb, maxnames = max_titles[msgtype];
1039     const char *old_title;
1040     const char *old_name;
1041    
1042     old_title = book->title;
1043     old_name = book->name;
1044    
1045     /* some pre-generated books have title already set (from
1046     * maps), also don't bother looking for unique title if
1047     * we already used up all the available names! */
1048 root 1.2
1049 root 1.5 if (!tl)
1050     {
1051     LOG (llevError, "change_book_name(): can't find title list\n");
1052     numb = 0;
1053     }
1054     else
1055     numb = tl->number;
1056 elmex 1.1
1057 root 1.5 if (numb == maxnames)
1058     {
1059 elmex 1.1 #ifdef ARCHIVE_DEBUG
1060 root 1.5 LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames);
1061 elmex 1.1 #endif
1062 root 1.5 break;
1063     }
1064     /* shouldnt change map-maker books */
1065     else if (!book->title)
1066     do
1067     {
1068     /* random book name */
1069     new_text_name (book, msgtype);
1070     add_author (book, msgtype); /* random author */
1071     tries++;
1072     }
1073     while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK);
1074    
1075     /* Now deal with 2 cases.
1076     * 1)If no space for a new title exists lets just restore
1077     * the old book properties. Remember, if the book had
1078     * matchd an older entry on the titlelist, we shouldnt
1079     * have called this routine in the first place!
1080     * 2) If we got a unique title, we need to add it to
1081     * the list.
1082     */
1083 elmex 1.1
1084 root 1.5 if (tries == MAX_TITLE_CHECK || numb == maxnames)
1085     { /* got to check maxnames again */
1086 elmex 1.1 #ifdef ARCHIVE_DEBUG
1087 root 1.5 LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames);
1088 elmex 1.1 #endif
1089 root 1.5 /* restore old book properties here */
1090     book->title = old_title;
1091    
1092     if (RANDOM () % 4)
1093     {
1094     /* Lets give the book a description to individualize it some */
1095     char new_name[MAX_BUF];
1096    
1097 root 1.19 snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[rndm (nbr)], old_name);
1098 root 1.2
1099 root 1.5 book->name = new_name;
1100     }
1101     else
1102     {
1103     book->name = old_name;
1104 root 1.2 }
1105 root 1.5 }
1106     else if (book->title && strlen (book->msg) > 5)
1107     { /* archive if long msg texts */
1108     add_book_to_list (book, msgtype);
1109     }
1110     }
1111     break;
1112 root 1.2 }
1113 elmex 1.1
1114 root 1.5 default:
1115 root 1.2 LOG (llevError, "change_book_name() called w/ illegal obj type.\n");
1116     return;
1117 root 1.5 }
1118 elmex 1.1 }
1119    
1120     /*****************************************************************************
1121     *
1122     * This is the start of the area that generates the actual contents
1123     * of the book.
1124     *
1125     *****************************************************************************/
1126    
1127     /*****************************************************************************
1128     * Monster msg generation code.
1129     ****************************************************************************/
1130    
1131     /* get_random_mon() - returns a random monster slected from linked
1132     * list of all monsters in the current game. If level is non-zero,
1133     * then only monsters greater than that level will be returned.
1134     * Changed 971225 to be greater than equal to level passed. Also
1135     * made choosing by level more random.
1136     */
1137    
1138     object *
1139     get_random_mon (int level)
1140     {
1141 root 1.5 objectlink *mon = first_mon_info;
1142     int i = 0, monnr;
1143    
1144     /* safety check. Problem w/ init_mon_info list? */
1145     if (!nrofmon || !mon)
1146     return (object *) NULL;
1147    
1148     if (!level)
1149     {
1150     /* lets get a random monster from the mon_info linked list */
1151     monnr = RANDOM () % nrofmon;
1152 elmex 1.1
1153 root 1.5 for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1154     if (i++ == monnr)
1155     break;
1156    
1157     if (!mon)
1158     {
1159     LOG (llevError, "get_random_mon: Didn't find a monster when we should have\n");
1160 root 1.2 return NULL;
1161 root 1.5 }
1162     return mon->ob;
1163     }
1164 elmex 1.1
1165 root 1.5 /* Case where we are searching by level. Redone 971225 to be clearer
1166     * and more random. Before, it looks like it took a random monster from
1167     * the list, and then returned the first monster after that which was
1168     * appropriate level. This wasn't very random because if you had a
1169     * bunch of low level monsters and then a high level one, if the random
1170     * determine took one of the low level ones, it would just forward to the
1171     * high level one and return that. Thus, monsters that immediatly followed
1172     * a bunch of low level monsters would be more heavily returned. It also
1173     * means some of the dragons would be poorly represented, since they
1174     * are a group of high level monsters all around each other.
1175     */
1176    
1177     /* First count number of monsters meeting level criteria */
1178     for (mon = first_mon_info, i = 0; mon; mon = mon->next)
1179     if (mon->ob->level >= level)
1180     i++;
1181    
1182     if (i == 0)
1183     {
1184     LOG (llevError, "get_random_mon() couldn't return monster for level %d\n", level);
1185     return NULL;
1186     }
1187    
1188     monnr = RANDOM () % i;
1189     for (mon = first_mon_info; mon; mon = mon->next)
1190     if (mon->ob->level >= level && monnr-- == 0)
1191     return mon->ob;
1192    
1193     if (!mon)
1194     {
1195     LOG (llevError, "get_random_mon(): didn't find a monster when we should have\n");
1196     return NULL;
1197     }
1198     return NULL; /* Should be unreached, by keeps warnings down */
1199 elmex 1.1 }
1200    
1201     /*
1202     * Returns a description of the monster. This really needs to be
1203     * redone, as describe_item really gives a pretty internal description.
1204     */
1205    
1206 root 1.5 char *
1207 elmex 1.1 mon_desc (const object *mon)
1208     {
1209 root 1.5 static char retbuf[HUGE_BUF];
1210 elmex 1.1
1211 root 1.5 sprintf (retbuf, " *** %s ***\n", &mon->name);
1212     strcat (retbuf, describe_item (mon, NULL));
1213 elmex 1.1
1214 root 1.5 return retbuf;
1215 elmex 1.1 }
1216    
1217    
1218     /* This function returns the next monsters after 'tmp'. If no match is
1219     * found, it returns NULL (changed 0.94.3 to do this, since the
1220     * calling function (mon_info_msg) seems to expect that.
1221     */
1222    
1223     object *
1224     get_next_mon (object *tmp)
1225     {
1226 root 1.5 objectlink *mon;
1227 elmex 1.1
1228 root 1.5 for (mon = first_mon_info; mon; mon = mon->next)
1229     if (mon->ob == tmp)
1230     break;
1231    
1232     /* didn't find a match */
1233     if (!mon)
1234     return NULL;
1235     if (mon->next)
1236     return mon->next->ob;
1237     else
1238     return first_mon_info->ob;
1239 elmex 1.1
1240     }
1241    
1242    
1243    
1244     /* mon_info_msg() - generate a message detailing the properties
1245     * of a randomly selected monster.
1246     */
1247    
1248 root 1.5 char *
1249 elmex 1.1 mon_info_msg (int level, int booksize)
1250     {
1251 root 1.5 static char retbuf[BOOK_BUF];
1252     char tmpbuf[HUGE_BUF];
1253     object *tmp;
1254    
1255     /*preamble */
1256     strcpy (retbuf, "This beastiary contains:");
1257    
1258     /* lets print info on as many monsters as will fit in our
1259     * document.
1260     * 8-96 Had to change this a bit, otherwise there would
1261     * have been an impossibly large number of combinations
1262     * of text! (and flood out the available number of titles
1263     * in the archive in a snap!) -b.t.
1264     */
1265     tmp = get_random_mon (level * 3);
1266     while (tmp)
1267     {
1268     /* monster description */
1269     sprintf (tmpbuf, "\n---\n%s", mon_desc (tmp));
1270    
1271     if (!book_overflow (retbuf, tmpbuf, booksize))
1272     strcat (retbuf, tmpbuf);
1273     else
1274     break;
1275 elmex 1.1
1276 root 1.5 /* Note that the value this returns is not based on level */
1277     tmp = get_next_mon (tmp);
1278 elmex 1.1 }
1279    
1280     #ifdef BOOK_MSG_DEBUG
1281 root 1.5 LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf));
1282     fprintf (logfile, " MADE THIS:\n%s\n", retbuf);
1283 elmex 1.1 #endif
1284    
1285 root 1.5 return retbuf;
1286 elmex 1.1 }
1287    
1288    
1289     /*****************************************************************************
1290     * Artifact msg generation code.
1291     ****************************************************************************/
1292    
1293     /* artifact_msg() - generate a message detailing the properties
1294     * of 1-6 artifacts drawn sequentially from the artifact list.
1295     */
1296 root 1.22 const char *
1297 elmex 1.1 artifact_msg (int level, int booksize)
1298     {
1299 root 1.5 artifactlist *al = NULL;
1300     artifact *art;
1301     int chance, i, type, index;
1302     int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1;
1303 root 1.22 const char *ch;
1304     char name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF];
1305 root 1.5 static char retbuf[BOOK_BUF];
1306     object *tmp = NULL;
1307    
1308     /* values greater than 5 create msg buffers that are too big! */
1309     if (book_entries > 5)
1310     book_entries = 5;
1311    
1312     /* lets determine what kind of artifact type randomly.
1313     * Right now legal artifacts only come from those listed
1314     * in art_name_array. Also, we check to be sure an artifactlist
1315     * for that type exists!
1316     */
1317     i = 0;
1318     do
1319     {
1320     index = RANDOM () % (sizeof (art_name_array) / sizeof (arttypename));
1321     type = art_name_array[index].type;
1322     al = find_artifactlist (type);
1323     i++;
1324     }
1325     while ((al == NULL) && (i < 10));
1326    
1327     if (i == 10) /* Unable to find a message */
1328 root 1.22 return "None";
1329 elmex 1.1
1330 root 1.5 /* There is no reason to start on the artifact list at the begining. Lets
1331     * take our starting position randomly... */
1332     art = al->items;
1333     for (i = RANDOM () % level + RANDOM () % 2 + 1; i > 0; i--)
1334     {
1335     if (art == NULL)
1336     art = al->items; /* hmm, out of stuff, loop back around */
1337     art = art->next;
1338     }
1339    
1340     /* the base 'generic' name for our artifact */
1341 root 1.21 assign (name, art_name_array[index].name);
1342 root 1.5
1343     /* Ok, lets print out the contents */
1344     sprintf (retbuf, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact");
1345    
1346     /* artifact msg attributes loop. Lets keep adding entries to the 'book'
1347     * as long as we have space up to the allowed max # (book_entires)
1348     */
1349     while (book_entries > 0)
1350     {
1351    
1352     if (art == NULL)
1353     art = al->items;
1354 elmex 1.1
1355 root 1.5 /* separator of items */
1356     strcpy (buf, "--- \n");
1357    
1358     /* Name */
1359     if (art->allowed != NULL && strcmp (art->allowed->name, "All"))
1360     {
1361     linked_char *temp, *next = art->allowed;
1362    
1363     do
1364 root 1.2 {
1365 root 1.5 temp = next;
1366     next = next->next;
1367 root 1.2 }
1368 root 1.5 while (next && !RANDOM () % 2);
1369     sprintf (buf, "%s A %s of %s", buf, &temp->name, &art->item->name);
1370     }
1371     else /* default name is used */
1372     sprintf (buf, "%s The %s of %s", buf, name, &art->item->name);
1373 root 1.2
1374 root 1.5 /* chance of finding */
1375     chance = (int) (100 * ((float) art->chance / al->total_chance));
1376     if (chance >= 20)
1377     sprintf (sbuf, "an uncommon");
1378     else if (chance >= 10)
1379     sprintf (sbuf, "an unusual");
1380     else if (chance >= 5)
1381     sprintf (sbuf, "a rare");
1382     else
1383     sprintf (sbuf, "a very rare");
1384     sprintf (buf, "%s is %s\n", buf, sbuf);
1385    
1386     /* value of artifact */
1387     sprintf (buf, "%s item with a value that is %d times normal.\n", buf, art->item->value);
1388    
1389     /* include the message about the artifact, if exists, and book
1390     * level is kinda high */
1391     if (art->item->msg && (RANDOM () % 4 + 1) < level && !((strlen (art->item->msg) + strlen (buf)) > BOOK_BUF))
1392     strcat (buf, art->item->msg);
1393    
1394     /* properties of the artifact */
1395 root 1.13 tmp = object::create ();
1396 root 1.5 add_abilities (tmp, art->item);
1397     tmp->type = type;
1398     SET_FLAG (tmp, FLAG_IDENTIFIED);
1399     if ((ch = describe_item (tmp, NULL)) != NULL && strlen (ch) > 1)
1400     sprintf (buf, "%s Properties of this artifact include: \n %s \n", buf, ch);
1401 root 1.13 tmp->destroy ();
1402 root 1.5 /* add the buf if it will fit */
1403     if (!book_overflow (retbuf, buf, booksize))
1404     strcat (retbuf, buf);
1405     else
1406     break;
1407 root 1.2
1408 root 1.5 art = art->next;
1409     book_entries--;
1410     }
1411 elmex 1.1
1412     #ifdef BOOK_MSG_DEBUG
1413 root 1.5 LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf));
1414     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1415 elmex 1.1 #endif
1416 root 1.5 return retbuf;
1417 elmex 1.1 }
1418    
1419     /*****************************************************************************
1420     * Spellpath message generation
1421     *****************************************************************************/
1422    
1423     /* spellpath_msg() - generate a message detailing the member
1424     * incantations/prayers (and some of their properties) belonging to
1425     * a given spellpath.
1426     */
1427    
1428 root 1.5 char *
1429 elmex 1.1 spellpath_msg (int level, int booksize)
1430     {
1431 root 1.5 static char retbuf[BOOK_BUF];
1432     char tmpbuf[BOOK_BUF];
1433     int path = RANDOM () % NRSPELLPATHS, prayers = RANDOM () % 2;
1434     int did_first_sp = 0;
1435     uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path];
1436     archetype *at;
1437    
1438     /* Preamble */
1439     sprintf (retbuf, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations");
1440    
1441     if (path == -1)
1442     strcat (retbuf, "having no known spell path.\n");
1443     else
1444     sprintf (retbuf, "%sbelonging to the path of %s:\n", retbuf, spellpathnames[path]);
1445    
1446 root 1.27 for_all_archetypes (at)
1447 root 1.5 {
1448     /* Determine if this is an appropriate spell. Must
1449     * be of matching path, must be of appropriate type (prayer
1450     * or not), and must be within the valid level range.
1451     */
1452 root 1.27 if (at->type == SPELL && at->path_attuned & pnum &&
1453     ((at->stats.grace && prayers) || (at->stats.sp && !prayers)) && (at->level < (level * 8)))
1454 root 1.5 {
1455 root 1.27 assign (tmpbuf, at->object::name);
1456 elmex 1.1
1457 root 1.5 if (book_overflow (retbuf, tmpbuf, booksize))
1458     break;
1459     else
1460     {
1461     if (did_first_sp)
1462     strcat (retbuf, ",\n");
1463     did_first_sp = 1;
1464     strcat (retbuf, tmpbuf);
1465 root 1.2 }
1466 root 1.5 }
1467 elmex 1.1 }
1468 root 1.5 /* Geez, no spells were generated. */
1469     if (!did_first_sp)
1470     {
1471     if (RANDOM () % 4) /* usually, lets make a recursive call... */
1472     spellpath_msg (level, booksize);
1473     else /* give up, cause knowing no spells exist for path is info too. */
1474     strcat (retbuf, "\n - no known spells exist -\n");
1475 elmex 1.1 }
1476 root 1.5 else
1477     {
1478     strcat (retbuf, "\n");
1479 elmex 1.1 }
1480 root 1.5 return retbuf;
1481 elmex 1.1 }
1482    
1483     /* formula_msg() - generate a message detailing the properties
1484     * of a randomly selected alchemical formula.
1485     */
1486 root 1.5 void
1487     make_formula_book (object *book, int level)
1488     {
1489     char retbuf[BOOK_BUF], title[MAX_BUF];
1490     recipelist *fl;
1491     recipe *formula = NULL;
1492     int chance;
1493    
1494     /* the higher the book level, the more complex (ie number of
1495     * ingredients) the formula can be.
1496     */
1497     fl = get_formulalist (((RANDOM () % level) / 3) + 1);
1498    
1499     if (!fl)
1500     fl = get_formulalist (1); /* safety */
1501    
1502     if (fl->total_chance == 0)
1503     {
1504     book->msg = "<indecipherable text>\n";
1505     new_text_name (book, 4);
1506     add_author (book, 4);
1507     return;
1508     }
1509    
1510     /* get a random formula, weighted by its bookchance */
1511     chance = RANDOM () % fl->total_chance;
1512     for (formula = fl->items; formula != NULL; formula = formula->next)
1513     {
1514     chance -= formula->chance;
1515     if (chance <= 0)
1516     break;
1517     }
1518    
1519     if (!formula || formula->arch_names <= 0)
1520     {
1521     book->msg = "<indecipherable text>\n";
1522     new_text_name (book, 4);
1523     add_author (book, 4);
1524    
1525 elmex 1.1 }
1526 root 1.5 else
1527     {
1528     /* looks like a formula was found. Base the amount
1529     * of information on the booklevel and the spellevel
1530     * of the formula. */
1531    
1532     const char *op_name = formula->arch_name[RANDOM () % formula->arch_names];
1533     archetype *at;
1534    
1535     /* preamble */
1536     sprintf (retbuf, "Herein is described a project using %s: \n", formula->skill ? &formula->skill : "an unknown skill");
1537    
1538 root 1.8 if ((at = archetype::find (op_name)) != (archetype *) NULL)
1539 root 1.27 op_name = at->object::name;
1540 root 1.5 else
1541     LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name);
1542 elmex 1.1
1543 root 1.5 /* item name */
1544     if (strcmp (formula->title, "NONE"))
1545     {
1546     sprintf (retbuf, "%sThe %s of %s", retbuf, op_name, &formula->title);
1547     /* This results in things like pile of philo. sulfur.
1548     * while philo. sulfur may look better, without this,
1549     * you get things like 'the wise' because its missing the
1550     * water of section.
1551     */
1552     sprintf (title, "%s: %s of %s",
1553     formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title);
1554 root 1.2 }
1555 root 1.5 else
1556 root 1.2 {
1557 root 1.5 sprintf (retbuf, "%sThe %s", retbuf, op_name);
1558     sprintf (title, "%s: %s", formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name);
1559 root 1.27 if (at->title)
1560 root 1.5 {
1561     strcat (retbuf, " ");
1562 root 1.27 strcat (retbuf, at->title);
1563 root 1.5 strcat (title, " ");
1564 root 1.27 strcat (title, at->title);
1565 root 1.2 }
1566     }
1567 root 1.5 /* Lets name the book something meaningful ! */
1568     book->name = title;
1569     book->title = NULL;
1570 root 1.2
1571 root 1.5 /* ingredients to make it */
1572     if (formula->ingred != NULL)
1573 root 1.2 {
1574 root 1.5 linked_char *next;
1575     archetype *at;
1576 root 1.2
1577 root 1.8 at = archetype::find (formula->cauldron);
1578 root 1.2
1579 root 1.5 sprintf (retbuf + strlen (retbuf),
1580 root 1.27 " may be made at %s using the following ingredients:\n", at ? query_name (at) : "an unknown place");
1581 root 1.2
1582 root 1.5 for (next = formula->ingred; next != NULL; next = next->next)
1583 root 1.2 {
1584 root 1.5 strcat (retbuf, next->name);
1585     strcat (retbuf, "\n");
1586 root 1.2 }
1587     }
1588 root 1.5 else
1589     LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title);
1590     if (retbuf[strlen (retbuf) - 1] != '\n')
1591     strcat (retbuf, "\n");
1592 root 1.3
1593 root 1.5 book->msg = retbuf;
1594 elmex 1.1 }
1595     }
1596    
1597     /* god_info_msg() - generate a message detailing the properties
1598     * of a random god. Used by the book hack. b.t.
1599     */
1600 root 1.5 const char *
1601 elmex 1.1 god_info_msg (int level, int booksize)
1602     {
1603 root 1.5 static char retbuf[BOOK_BUF];
1604     const char *name = NULL;
1605     char buf[BOOK_BUF];
1606     int i;
1607     size_t introlen;
1608     object *god = pntr_to_god_obj (get_rand_god ());
1609    
1610     if (!god)
1611     return (char *) NULL; /* oops, problems... */
1612     name = god->name;
1613    
1614     /* preamble.. */
1615     sprintf (retbuf, "This document contains knowledge concerning\n");
1616     sprintf (retbuf, "%sthe diety %s", retbuf, name);
1617    
1618     /* Always have as default information the god's descriptive terms. */
1619     if (nstrtok (god->msg, ",") > 0)
1620     {
1621     strcat (retbuf, ", known as");
1622     strcat (retbuf, strtoktolin (god->msg, ","));
1623     }
1624     else
1625     strcat (retbuf, "...");
1626    
1627     strcat (retbuf, "\n ---\n");
1628     introlen = strlen (retbuf); /* so we will know if no new info is added later */
1629 elmex 1.1
1630 root 1.5 /* Information about the god is random, and based on the level of the
1631     * 'book'. Probably there is a more intellegent way to implement
1632     * this ...
1633     */
1634    
1635     while (level > 0)
1636     {
1637     sprintf (buf, " ");
1638     if (level == 2 && RANDOM () % 2)
1639     { /* enemy god */
1640     const char *enemy = god->title;
1641 elmex 1.1
1642 root 1.5 if (enemy)
1643     sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy);
1644     }
1645 root 1.22
1646 root 1.5 if (level == 3 && RANDOM () % 2)
1647     { /* enemy race, what the god's holy word effects */
1648     const char *enemy = god->slaying;
1649    
1650     if (enemy && !(god->path_denied & PATH_TURNING))
1651     if ((i = nstrtok (enemy, ",")) > 0)
1652     {
1653     char tmpbuf[MAX_BUF];
1654    
1655     sprintf (buf, "The holy words of %s have the power to\n", name);
1656     strcat (buf, "slay creatures belonging to the ");
1657     if (i > 1)
1658     sprintf (tmpbuf, "following \n races:%s", strtoktolin (enemy, ","));
1659     else
1660     sprintf (tmpbuf, "race of%s", strtoktolin (enemy, ","));
1661     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1662     }
1663     }
1664 root 1.22
1665 root 1.5 if (level == 4 && RANDOM () % 2)
1666     { /* Priest of god gets these protect,vulnerable... */
1667 root 1.22 char tmpbuf[MAX_BUF];
1668 root 1.5
1669 root 1.22 if (const char *cp = describe_resistance (god, 1))
1670 root 1.5 { /* This god does have protections */
1671     sprintf (tmpbuf, "%s has a potent aura which is extended\n", name);
1672     strcat (tmpbuf, "faithful priests. The effects of this aura include:\n");
1673     strcat (tmpbuf, cp);
1674     strcat (buf, tmpbuf);
1675     strcat (buf, "\n ---\n");
1676     }
1677     else
1678     sprintf (buf, " ");
1679     }
1680 root 1.22
1681 root 1.5 if (level == 5 && RANDOM () % 2)
1682     { /* aligned race, summoning */
1683     const char *race = god->race; /* aligned race */
1684    
1685     if (race && !(god->path_denied & PATH_SUMMON))
1686     if ((i = nstrtok (race, ",")) > 0)
1687     {
1688     char tmpbuf[MAX_BUF];
1689    
1690     sprintf (buf, "Creatures sacred to %s include the \n", name);
1691     if (i > 1)
1692     sprintf (tmpbuf, "following \n races:%s", strtoktolin (race, ","));
1693     else
1694     sprintf (tmpbuf, "race of%s", strtoktolin (race, ","));
1695     sprintf (buf, "%s%s\n ---\n", buf, tmpbuf);
1696     }
1697     }
1698 root 1.22
1699 root 1.5 if (level == 6 && RANDOM () % 2)
1700     { /* blessing,curse properties of the god */
1701 root 1.22 char tmpbuf[MAX_BUF];
1702 root 1.5
1703 root 1.22 if (const char *cp = describe_resistance (god, 1))
1704 root 1.5 { /* This god does have protections */
1705     sprintf (tmpbuf, "\nThe priests of %s are known to be able to \n", name);
1706     strcat (tmpbuf, "bestow a blessing which makes the recipient\n");
1707     strcat (tmpbuf, cp);
1708     strcat (buf, tmpbuf);
1709     strcat (buf, "\n ---\n");
1710 root 1.2 }
1711 root 1.5 else
1712     sprintf (buf, " ");
1713    
1714     }
1715 root 1.22
1716 root 1.5 if (level == 8 && RANDOM () % 2)
1717     { /* immunity, holy possession */
1718     int has_effect = 0, tmpvar;
1719     char tmpbuf[MAX_BUF];
1720    
1721     sprintf (tmpbuf, "\n");
1722     sprintf (tmpbuf, "The priests of %s are known to make cast a mighty \n", name);
1723    
1724     strcat (tmpbuf, "prayer of possession which gives the recipient\n");
1725    
1726     for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++)
1727     {
1728     if (god->resist[tmpvar] == 100)
1729     {
1730     has_effect = 1;
1731     sprintf (tmpbuf + strlen (tmpbuf), "Immunity to %s", attacktype_desc[tmpvar]);
1732 root 1.2 }
1733     }
1734 root 1.22
1735 root 1.5 if (has_effect)
1736     {
1737     strcat (buf, tmpbuf);
1738     strcat (buf, "\n ---\n");
1739     }
1740     else
1741     sprintf (buf, " ");
1742     }
1743 root 1.22
1744 root 1.5 if (level == 12 && RANDOM () % 2)
1745     { /* spell paths */
1746     int has_effect = 0, tmpvar;
1747     char tmpbuf[MAX_BUF];
1748    
1749     sprintf (tmpbuf, "\n");
1750     sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name);
1751     strcat (tmpbuf, "are mystically transformed. Effects of this include:\n");
1752 root 1.22
1753 root 1.5 if ((tmpvar = god->path_attuned))
1754     {
1755     has_effect = 1;
1756     DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned");
1757 root 1.2 }
1758 root 1.22
1759 root 1.5 if ((tmpvar = god->path_repelled))
1760     {
1761     has_effect = 1;
1762     DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled");
1763 root 1.2 }
1764 root 1.22
1765 root 1.5 if ((tmpvar = god->path_denied))
1766     {
1767     has_effect = 1;
1768     DESCRIBE_PATH (tmpbuf, tmpvar, "Denied");
1769 root 1.2 }
1770 root 1.22
1771 root 1.5 if (has_effect)
1772     {
1773     strcat (buf, tmpbuf);
1774     strcat (buf, "\n ---\n");
1775 root 1.2 }
1776 root 1.5 else
1777     sprintf (buf, " ");
1778     }
1779 root 1.2
1780 root 1.5 /* check to be sure new buffer size dont exceed either
1781     * the maximum buffer size, or the 'natural' size of the
1782     * book...
1783     */
1784     if (book_overflow (retbuf, buf, booksize))
1785     break;
1786     else if (strlen (buf) > 1)
1787     strcat (retbuf, buf);
1788 root 1.22
1789 root 1.5 level--;
1790     }
1791 root 1.22
1792 root 1.5 if (strlen (retbuf) == introlen)
1793     { /* we got no information beyond the preamble! */
1794     strcat (retbuf, " [Unfortunately the rest of the information is\n");
1795     strcat (retbuf, " hopelessly garbled!]\n ---\n");
1796     }
1797 elmex 1.1 #ifdef BOOK_MSG_DEBUG
1798 root 1.5 LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf));
1799     fprintf (logfile, " MADE THIS:\n%s", retbuf);
1800 elmex 1.1 #endif
1801 root 1.5 return retbuf;
1802 elmex 1.1 }
1803    
1804     /* tailor_readable_ob()- The main routine. This chooses a random
1805     * message to put in given readable object (type==BOOK) which will
1806     * be referred hereafter as a 'book'. We use the book level to de-
1807     * termine the value of the information we will insert. Higher
1808     * values mean the book will (generally) have better/more info.
1809     * See individual cases as to how this will be utilized.
1810     * "Book" name/content length are based on the weight of the
1811     * document. If the value of msg_type is negative, we will randomly
1812     * choose the kind of message to generate.
1813     * -b.t. thomas@astro.psu.edu
1814     *
1815     * book is the object we are creating into.
1816     * If msg_type is a positive value, we use that to determine the
1817     * message type - otherwise a random value is used.
1818     *
1819     */
1820 root 1.5 void
1821 elmex 1.1 tailor_readable_ob (object *book, int msg_type)
1822     {
1823 root 1.5 char msgbuf[BOOK_BUF];
1824     int level = book->level ? (RANDOM () % book->level) + 1 : 1;
1825     int book_buf_size;
1826    
1827     /* safety */
1828     if (book->type != BOOK)
1829     return;
1830    
1831     if (level <= 0)
1832     return; /* if no level no point in doing any more... */
1833    
1834     /* Max text length this book can have. */
1835     book_buf_size = BOOKSIZE (book);
1836    
1837     /* &&& The message switch &&& */
1838     /* Below all of the possible types of messages in the "book"s.
1839     */
1840     /*
1841     * IF you add a new type of book msg, you will have to do several things.
1842     * 1) make sure there is an entry in the msg switch below!
1843     * 2) make sure there is an entry in max_titles[] array.
1844     * 3) make sure there are entries for your case in new_text_title()
1845     * and add_authour().
1846     * 4) you may want separate authour/book name arrays in read.h
1847     */
1848    
1849     msg_type = msg_type > 0 ? msg_type : (RANDOM () % 6);
1850     switch (msg_type)
1851     {
1852 root 1.24 case 1: /* monster attrib */
1853     strcpy (msgbuf, mon_info_msg (level, book_buf_size));
1854     break;
1855     case 2: /* artifact attrib */
1856     strcpy (msgbuf, artifact_msg (level, book_buf_size));
1857     break;
1858     case 3: /* grouping incantations/prayers by path */
1859     strcpy (msgbuf, spellpath_msg (level, book_buf_size));
1860     break;
1861     case 4: /* describe an alchemy formula */
1862     make_formula_book (book, level);
1863     /* make_formula_book already gives title */
1864     return;
1865     break;
1866     case 5: /* bits of information about a god */
1867     strcpy (msgbuf, god_info_msg (level, book_buf_size));
1868     break;
1869     case 0: /* use info list in lib/ */
1870     default:
1871     cfperl_make_book (book, level);
1872     return;
1873 root 1.5 }
1874 elmex 1.1
1875 root 1.5 strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */
1876 root 1.10
1877 root 1.5 if (strlen (msgbuf) > 1)
1878     {
1879     book->msg = msgbuf;
1880     /* lets give the "book" a new name, which may be a compound word */
1881     change_book (book, msg_type);
1882     }
1883 elmex 1.1
1884     }
1885    
1886    
1887     /*****************************************************************************
1888     *
1889     * Cleanup routine for readble stuff.
1890     *
1891     *****************************************************************************/
1892    
1893 root 1.5 void
1894 elmex 1.1 free_all_readable (void)
1895     {
1896 root 1.5 titlelist *tlist, *tnext;
1897     title *title1, *titlenext;
1898     linked_char *lmsg, *nextmsg;
1899     objectlink *monlink, *nextmon;
1900    
1901     LOG (llevDebug, "freeing all book information\n");
1902    
1903     for (tlist = booklist; tlist != NULL; tlist = tnext)
1904     {
1905     tnext = tlist->next;
1906    
1907     for (title1 = tlist->first_book; title1; title1 = titlenext)
1908     {
1909     titlenext = title1->next;
1910     delete title1;
1911     }
1912    
1913     delete tlist;
1914     }
1915 root 1.10
1916 root 1.5 for (lmsg = first_msg; lmsg; lmsg = nextmsg)
1917     {
1918     nextmsg = lmsg->next;
1919     delete lmsg;
1920     }
1921 root 1.10
1922 root 1.5 for (monlink = first_mon_info; monlink; monlink = nextmon)
1923     {
1924     nextmon = monlink->next;
1925 root 1.11 delete monlink;
1926 root 1.5 }
1927 elmex 1.1 }
1928    
1929    
1930     /*****************************************************************************
1931     *
1932     * Writeback routine for updating the bookarchive.
1933     *
1934     ****************************************************************************/
1935    
1936     /* write_book_archive() - write out the updated book archive */
1937    
1938 root 1.5 void
1939 elmex 1.1 write_book_archive (void)
1940     {
1941 root 1.5 FILE *fp;
1942     int index = 0;
1943     char fname[MAX_BUF];
1944     title *book = NULL;
1945     titlelist *bl = get_titlelist (0);
1946    
1947     /* If nothing changed, don't write anything */
1948     if (!need_to_write_bookarchive)
1949     return;
1950     need_to_write_bookarchive = 0;
1951    
1952     sprintf (fname, "%s/bookarch", settings.localdir);
1953     LOG (llevDebug, "Updating book archive: %s...\n", fname);
1954    
1955     if ((fp = fopen (fname, "w")) == NULL)
1956     {
1957     LOG (llevDebug, "Can't open book archive file %s\n", fname);
1958     }
1959     else
1960     {
1961     while (bl)
1962     {
1963     for (book = bl->first_book; book; book = book->next)
1964     if (book && book->authour)
1965     {
1966     fprintf (fp, "title %s\n", &book->name);
1967     fprintf (fp, "authour %s\n", &book->authour);
1968     fprintf (fp, "arch %s\n", &book->archname);
1969     fprintf (fp, "level %d\n", book->level);
1970     fprintf (fp, "type %d\n", index);
1971     fprintf (fp, "size %d\n", book->size);
1972     fprintf (fp, "index %d\n", book->msg_index);
1973     fprintf (fp, "end\n");
1974     }
1975     bl = bl->next;
1976     index++;
1977     }
1978     fclose (fp);
1979     chmod (fname, SAVE_MODE);
1980     }
1981     }
1982     readable_message_type *
1983     get_readable_message_type (object *readable)
1984     {
1985     uint8 subtype = readable->subtype;
1986    
1987     if (subtype > last_readable_subtype)
1988     return &(readable_message_types[0]);
1989     return &(readable_message_types[subtype]);
1990 elmex 1.1 }