1 | /* |
1 | /* |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
2 | * This file is part of Deliantra, the Roguelike Realtime MMORPG. |
3 | * |
3 | * |
|
|
4 | * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team |
4 | * Copyright (©) 2005,2006,2007,2008,2009,2010 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team |
5 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 2002 Mark Wedel & Crossfire Development Team |
6 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * Copyright (©) 1992 Frank Tore Johansen |
7 | * |
8 | * |
8 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * Deliantra is free software: you can redistribute it and/or modify it under |
9 | * the terms of the Affero GNU General Public License as published by the |
10 | * the terms of the Affero GNU General Public License as published by the |
10 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * Free Software Foundation, either version 3 of the License, or (at your |
11 | * option) any later version. |
12 | * option) any later version. |
12 | * |
13 | * |
13 | * This program is distributed in the hope that it will be useful, |
14 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. |
17 | * GNU General Public License for more details. |
17 | * |
18 | * |
18 | * You should have received a copy of the Affero GNU General Public License |
19 | * You should have received a copy of the Affero GNU General Public License |
19 | * and the GNU General Public License along with this program. If not, see |
20 | * and the GNU General Public License along with this program. If not, see |
20 | * <http://www.gnu.org/licenses/>. |
21 | * <http://www.gnu.org/licenses/>. |
21 | * |
22 | * |
22 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | * The authors can be reached via e-mail to <support@deliantra.net> |
23 | */ |
24 | */ |
24 | |
25 | |
25 | /* This file contains code relevant to the BOOKS hack -- designed |
26 | /* This file contains code relevant to the BOOKS hack -- designed |
26 | * to allow randomly occuring messages in non-magical texts. |
27 | * to allow randomly occuring messages in non-magical texts. |
… | |
… | |
31 | #include <global.h> |
32 | #include <global.h> |
32 | #include <book.h> |
33 | #include <book.h> |
33 | #include <living.h> |
34 | #include <living.h> |
34 | #include <spells.h> |
35 | #include <spells.h> |
35 | |
36 | |
36 | /* Define this if you want to archive book titles by contents. |
37 | /* Define this if you want to archive book titles by contents. |
37 | * This option should enforce UNIQUE combinations of titles,authors and |
38 | * This option should enforce UNIQUE combinations of titles,authors and |
38 | * msg contents during and *between* game sessions. |
39 | * msg contents during and *between* game sessions. |
39 | * Note: a slight degeneracy exists since books are archived based on an integer |
40 | * Note: a slight degeneracy exists since books are archived based on an integer |
40 | * index value calculated from the message text (similar to alchemy formulae). |
41 | * index value calculated from the message text (similar to alchemy formulae). |
41 | * Sometimes two widely different messages have the same index value (rare). In |
42 | * Sometimes two widely different messages have the same index value (rare). In |
42 | * this case, it is possible to occasionally generate 2 books with same title and |
43 | * this case, it is possible to occasionally generate 2 books with same title and |
43 | * different message content. Not really a bug, but rather a feature. This action |
44 | * different message content. Not really a bug, but rather a feature. This action |
44 | * should keeps player on their toes ;). |
45 | * should keeps player on their toes ;). |
45 | * Also, note that there is *finite* space available for archiving message and titles. |
46 | * Also, note that there is *finite* space available for archiving message and titles. |
46 | * Once this space is used, books will stop being archived. Not a serious problem |
47 | * Once this space is used, books will stop being archived. Not a serious problem |
47 | * under the current regime, since there are generally fewer possible (random) |
48 | * under the current regime, since there are generally fewer possible (random) |
48 | * messages than space available on the titlelists. |
49 | * messages than space available on the titlelists. |
49 | * One exception (for sure) are the monster messages. But no worries, you should |
50 | * One exception (for sure) are the monster messages. But no worries, you should |
50 | * see all of the monster info in some order (but not all possble combinations) |
51 | * see all of the monster info in some order (but not all possble combinations) |
51 | * before the monster titlelist space is run out. You can increase titlelist |
52 | * before the monster titlelist space is run out. You can increase titlelist |
52 | * space by increasing the array sizes for the monster book_authours and book_names |
53 | * space by increasing the array sizes for the monster book_authours and book_names |
53 | * (see max_titles[] array and include/read.h). Since the unique_book algorthm is |
54 | * (see max_titles[] array and include/read.h). Since the unique_book algorthm is |
54 | * kinda stupid, this program *may* slow down program execution if defined (but I don't |
55 | * kinda stupid, this program *may* slow down program execution if defined (but I don't |
55 | * think its a significant problem, at least, I have no problems running this option |
56 | * think its a significant problem, at least, I have no problems running this option |
56 | * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg |
57 | * on a Sparc 10! Also, once archive title lists are filled and/or all possible msg |
57 | * combinations have been generated, unique_book isnt called anymore. It takes 5-10 |
58 | * combinations have been generated, unique_book isnt called anymore. It takes 5-10 |
58 | * sessions for this to happen). |
59 | * sessions for this to happen). |
59 | * Final note: the game remembers book/title/msg combinations from reading the |
60 | * Final note: the game remembers book/title/msg combinations from reading the |
60 | * file lib/bookarch. If you REMOVE this file, you will lose your archive. So |
61 | * file lib/bookarch. If you REMOVE this file, you will lose your archive. So |
61 | * be sure to copy it over to the new lib directory when you change versions. |
62 | * be sure to copy it over to the new lib directory when you change versions. |
62 | * -b.t. |
63 | * -b.t. |
63 | */ |
64 | */ |
64 | |
65 | |
65 | /* This flag is useful to see what kind of output messages are created */ |
66 | /* This flag is useful to see what kind of output messages are created */ |
66 | |
67 | |
… | |
… | |
401 | static const char *const book_descrpt[] = { |
402 | static const char *const book_descrpt[] = { |
402 | "ancient", |
403 | "ancient", |
403 | "cryptic", |
404 | "cryptic", |
404 | "cryptical", |
405 | "cryptical", |
405 | "dusty", |
406 | "dusty", |
406 | "hiearchical", |
407 | "hierarchical", |
407 | "grizzled", |
408 | "grizzled", |
408 | "gold-guilt", |
409 | "gold-guilt", |
409 | "great", |
410 | "great", |
410 | "lost", |
411 | "lost", |
411 | "magnificent", |
412 | "magnificent", |
… | |
… | |
534 | /* get_titlelist() - returns pointer to the title list referanced by i */ |
535 | /* get_titlelist() - returns pointer to the title list referanced by i */ |
535 | |
536 | |
536 | static titlelist * |
537 | static titlelist * |
537 | get_titlelist (int i) |
538 | get_titlelist (int i) |
538 | { |
539 | { |
|
|
540 | if (!booklist) |
|
|
541 | booklist = get_empty_booklist (); |
|
|
542 | |
539 | titlelist *tl = booklist; |
543 | titlelist *tl = booklist; |
540 | int number = i; |
544 | int number = i; |
541 | |
545 | |
542 | if (number < 0) |
546 | if (number < 0) |
543 | return tl; |
547 | return tl; |
… | |
… | |
546 | { |
550 | { |
547 | if (!tl->next) |
551 | if (!tl->next) |
548 | tl->next = get_empty_booklist (); |
552 | tl->next = get_empty_booklist (); |
549 | |
553 | |
550 | tl = tl->next; |
554 | tl = tl->next; |
551 | number--; |
555 | --number; |
552 | } |
556 | } |
553 | |
557 | |
554 | return tl; |
558 | return tl; |
555 | } |
559 | } |
556 | |
560 | |
557 | /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file |
561 | /* HANDMADE STRING FUNCTIONS.., perhaps these belong in another file |
558 | * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */ |
562 | * (shstr.c ?), but the quantity BOOK_BUF will need to be defined. */ |
559 | |
563 | |
560 | /* nstrtok() - simple routine to return the number of list |
564 | /* nstrtok() - simple routine to return the number of list |
561 | * items in buf1 as separated by the value of buf2 |
565 | * items in buf1 as separated by the value of buf2 |
562 | */ |
566 | */ |
… | |
… | |
566 | char *tbuf, sbuf[12], buf[MAX_BUF]; |
570 | char *tbuf, sbuf[12], buf[MAX_BUF]; |
567 | int number = 0; |
571 | int number = 0; |
568 | |
572 | |
569 | if (!buf1 || !buf2) |
573 | if (!buf1 || !buf2) |
570 | return 0; |
574 | return 0; |
571 | sprintf (buf, "%s", buf1); |
575 | |
572 | sprintf (sbuf, "%s", buf2); |
576 | strcpy (buf, buf1); |
|
|
577 | strcpy (sbuf, buf2); |
|
|
578 | |
573 | tbuf = strtok (buf, sbuf); |
579 | tbuf = strtok (buf, sbuf); |
574 | while (tbuf) |
580 | while (tbuf) |
575 | { |
581 | { |
576 | number++; |
582 | number++; |
577 | tbuf = strtok (NULL, sbuf); |
583 | tbuf = strtok (NULL, sbuf); |
… | |
… | |
596 | strcpy (rbuf, " "); |
602 | strcpy (rbuf, " "); |
597 | tbuf = strtok (buf, sbuf); |
603 | tbuf = strtok (buf, sbuf); |
598 | while (tbuf && i > 0) |
604 | while (tbuf && i > 0) |
599 | { |
605 | { |
600 | strcat (rbuf, tbuf); |
606 | strcat (rbuf, tbuf); |
|
|
607 | |
601 | i--; |
608 | i--; |
602 | if (i == 1 && maxi > 1) |
609 | if (i == 1 && maxi > 1) |
603 | strcat (rbuf, " and "); |
610 | strcat (rbuf, " and "); |
604 | else if (i > 0 && maxi > 1) |
611 | else if (i > 0 && maxi > 1) |
605 | strcat (rbuf, ", "); |
612 | strcat (rbuf, ", "); |
606 | else |
613 | else |
607 | strcat (rbuf, "."); |
614 | strcat (rbuf, "."); |
|
|
615 | |
608 | tbuf = strtok (NULL, sbuf); |
616 | tbuf = strtok (NULL, sbuf); |
609 | } |
617 | } |
|
|
618 | |
610 | return (char *) rbuf; |
619 | return rbuf; |
611 | } |
620 | } |
612 | |
621 | |
613 | /***************************************************************************** |
622 | /***************************************************************************** |
614 | * |
623 | * |
615 | * Start of initialisation related functions. |
624 | * Start of initialisation related functions. |
… | |
… | |
621 | * created and updated across multiple runs of the program. |
630 | * created and updated across multiple runs of the program. |
622 | */ |
631 | */ |
623 | static void |
632 | static void |
624 | init_book_archive () |
633 | init_book_archive () |
625 | { |
634 | { |
626 | FILE *fp; |
|
|
627 | int comp, nroftitle = 0; |
635 | int nroftitle = 0; |
628 | char buf[MAX_BUF], fname[MAX_BUF], *cp; |
|
|
629 | title *book = NULL; |
|
|
630 | titlelist *bl = get_empty_booklist (); |
636 | titlelist *bl = get_empty_booklist (); |
631 | static int did_init_barch; |
|
|
632 | |
637 | |
633 | if (did_init_barch) |
638 | object_thawer thawer (settings.localdir, "bookarch"); |
|
|
639 | |
|
|
640 | if (!thawer) |
|
|
641 | { |
|
|
642 | LOG (llevDebug, "could not read bookarch file\n"); |
634 | return; |
643 | return; |
635 | |
|
|
636 | did_init_barch = 1; |
|
|
637 | |
|
|
638 | if (!booklist) |
|
|
639 | booklist = bl; |
|
|
640 | |
|
|
641 | sprintf (fname, "%s/bookarch", settings.localdir); |
|
|
642 | LOG (llevDebug, " Reading bookarch from %s...\n", fname); |
|
|
643 | |
|
|
644 | if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL) |
|
|
645 | { |
644 | } |
|
|
645 | |
|
|
646 | while (thawer.kw) |
|
|
647 | { |
|
|
648 | if (thawer.kw != KW_title) |
|
|
649 | if (!thawer.parse_error ("bookarch file")) |
|
|
650 | break; |
|
|
651 | |
|
|
652 | title *book = get_empty_book (); /* init new book entry */ |
|
|
653 | thawer.get (book->name); |
|
|
654 | |
646 | int value, type = 0; |
655 | int type = -1; |
647 | size_t i; |
|
|
648 | |
656 | |
649 | while (fgets (buf, MAX_BUF, fp) != NULL) |
657 | for (;;) |
650 | { |
658 | { |
651 | if (*buf == '#') |
659 | thawer.next (); |
652 | continue; |
660 | |
653 | if ((cp = strchr (buf, '\n')) != NULL) |
661 | switch (thawer.kw) |
654 | *cp = '\0'; |
|
|
655 | cp = buf; |
|
|
656 | while (*cp == ' ') /* Skip blanks */ |
|
|
657 | cp++; |
|
|
658 | if (!strncmp (cp, "title", 4)) |
|
|
659 | { |
662 | { |
660 | book = get_empty_book (); /* init new book entry */ |
663 | case KW_type: thawer.get (type ); break; |
661 | book->name = strchr (cp, ' ') + 1; |
664 | case KW_authour: thawer.get (book->authour ); break; |
662 | type = -1; |
665 | case KW_arch: thawer.get (book->archname ); break; |
663 | nroftitle++; |
666 | case KW_level: thawer.get (book->level ); break; |
664 | continue; |
667 | case KW_size: thawer.get (book->size ); break; |
665 | } |
668 | case KW_index: thawer.get (book->msg_index); break; |
666 | if (!strncmp (cp, "authour", 4)) |
669 | |
667 | { |
670 | case KW_end: |
668 | book->authour = strchr (cp, ' ') + 1; |
|
|
669 | } |
|
|
670 | if (!strncmp (cp, "arch", 4)) |
|
|
671 | { |
|
|
672 | book->archname = strchr (cp, ' ') + 1; |
|
|
673 | } |
|
|
674 | else if (sscanf (cp, "level %d", &value)) |
|
|
675 | { |
|
|
676 | book->level = (uint16) value; |
|
|
677 | } |
|
|
678 | else if (sscanf (cp, "type %d", &value)) |
|
|
679 | { |
|
|
680 | type = (uint16) value; |
|
|
681 | } |
|
|
682 | else if (sscanf (cp, "size %d", &value)) |
|
|
683 | { |
|
|
684 | book->size = (uint16) value; |
|
|
685 | } |
|
|
686 | else if (sscanf (cp, "index %d", &value)) |
|
|
687 | { |
|
|
688 | book->msg_index = (uint16) value; |
|
|
689 | } |
|
|
690 | else if (!strncmp (cp, "end", 3)) |
|
|
691 | { /* link it */ |
671 | /* link it */ |
692 | bl = get_titlelist (type); |
672 | bl = get_titlelist (type); |
693 | book->next = bl->first_book; |
673 | book->next = bl->first_book; |
694 | bl->first_book = book; |
674 | bl->first_book = book; |
695 | bl->number++; |
675 | bl->number++; |
|
|
676 | ++nroftitle; |
|
|
677 | goto book_done; |
|
|
678 | |
|
|
679 | default: |
|
|
680 | delete book; |
|
|
681 | goto book_done; |
696 | } |
682 | } |
697 | } |
683 | } |
|
|
684 | |
|
|
685 | book_done: |
|
|
686 | thawer.next (); |
|
|
687 | } |
|
|
688 | |
698 | LOG (llevDebug, "book archives(used/avail): \n"); |
689 | LOG (llevDebug, "book archives(used/avail): \n"); |
|
|
690 | int i; |
699 | for (bl = booklist, i = 0; bl != NULL && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++) |
691 | for (bl = booklist, i = 0; bl && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++) |
700 | { |
|
|
701 | LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]); |
692 | LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]); |
702 | } |
|
|
703 | close_and_delete (fp, comp); |
|
|
704 | } |
|
|
705 | |
693 | |
706 | #ifdef BOOK_MSG_DEBUG |
|
|
707 | LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle); |
694 | LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle); |
708 | #endif |
|
|
709 | LOG (llevDebug, " done.\n"); |
|
|
710 | } |
695 | } |
711 | |
696 | |
712 | /* init_mon_info() - creates the linked list of pointers to |
697 | /* init_mon_info() - creates the linked list of pointers to |
713 | * monster archetype objects if not called previously |
698 | * monster archetype objects if not called previously |
714 | */ |
699 | */ |
715 | static void |
700 | static void |
716 | init_mon_info () |
701 | init_mon_info () |
717 | { |
702 | { |
… | |
… | |
737 | } |
722 | } |
738 | |
723 | |
739 | LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon); |
724 | LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon); |
740 | } |
725 | } |
741 | |
726 | |
742 | /* init_readable() - initialise linked lists utilized by |
727 | /* init_readable() - initialise linked lists utilized by |
743 | * message functions in tailor_readable_ob() |
728 | * message functions in tailor_readable_ob() |
744 | * |
729 | * |
745 | * This is the function called by the main routine to initialise |
730 | * This is the function called by the main routine to initialise |
746 | * all the readable information. |
731 | * all the readable information. |
747 | */ |
732 | */ |
748 | void |
733 | void |
… | |
… | |
798 | |
783 | |
799 | return t; |
784 | return t; |
800 | } |
785 | } |
801 | |
786 | |
802 | /* new_text_name() - Only for objects of type BOOK. SPELLBOOK stuff is |
787 | /* new_text_name() - Only for objects of type BOOK. SPELLBOOK stuff is |
803 | * handled directly in change_book_name(). Names are based on text |
788 | * handled directly in change_book_name(). Names are based on text |
804 | * msgtype |
789 | * msgtype |
805 | * this sets book book->name based on msgtype given. What name |
790 | * this sets book book->name based on msgtype given. What name |
806 | * is given is based on various criteria |
791 | * is given is based on various criteria |
807 | */ |
792 | */ |
808 | static void |
793 | static void |
809 | new_text_name (object *book, int msgtype) |
794 | new_text_name (object *book, int msgtype) |
810 | { |
795 | { |
811 | int nbr; |
796 | const char *name; |
812 | char name[MAX_BUF]; |
|
|
813 | |
797 | |
814 | if (book->type != BOOK) |
798 | if (book->type != BOOK) |
815 | return; |
799 | return; |
816 | |
800 | |
817 | switch (msgtype) |
801 | switch (msgtype) |
818 | { |
802 | { |
819 | case 1: /*monster */ |
803 | case 1: /*monster */ |
820 | nbr = sizeof (mon_book_name) / sizeof (char *); |
804 | name = mon_book_name[rndm (array_length (mon_book_name))]; |
821 | assign (name, mon_book_name[rndm (nbr)]); |
|
|
822 | break; |
805 | break; |
823 | case 2: /*artifact */ |
806 | case 2: /*artifact */ |
824 | nbr = sizeof (art_book_name) / sizeof (char *); |
807 | name = art_book_name[rndm (array_length (art_book_name))]; |
825 | assign (name, art_book_name[rndm (nbr)]); |
|
|
826 | break; |
808 | break; |
827 | case 3: /*spellpath */ |
809 | case 3: /*spellpath */ |
828 | nbr = sizeof (path_book_name) / sizeof (char *); |
810 | name = path_book_name[rndm (array_length (path_book_name))]; |
829 | assign (name, path_book_name[rndm (nbr)]); |
|
|
830 | break; |
811 | break; |
831 | case 4: /*alchemy */ |
812 | case 4: /*alchemy */ |
832 | nbr = sizeof (formula_book_name) / sizeof (char *); |
813 | name = formula_book_name[rndm (array_length (formula_book_name))]; |
833 | assign (name, formula_book_name[rndm (nbr)]); |
|
|
834 | break; |
814 | break; |
835 | case 5: /*gods */ |
815 | case 5: /*gods */ |
836 | nbr = sizeof (gods_book_name) / sizeof (char *); |
816 | name = gods_book_name[rndm (array_length (gods_book_name))]; |
837 | assign (name, gods_book_name[rndm (nbr)]); |
|
|
838 | break; |
817 | break; |
839 | case 6: /*msg file */ |
818 | case 6: /*msg file */ |
840 | default: |
819 | default: |
841 | if (book->weight > 2000) |
820 | name = book->weight > 2000 /* based on weight */ |
842 | { /* based on weight */ |
821 | ? heavy_book_name [rndm (array_length (heavy_book_name))] |
843 | nbr = sizeof (heavy_book_name) / sizeof (char *); |
822 | : light_book_name [rndm (array_length (light_book_name))]; |
844 | assign (name, heavy_book_name[rndm (nbr)]); |
|
|
845 | } |
|
|
846 | else if (book->weight < 2001) |
|
|
847 | { |
|
|
848 | nbr = sizeof (light_book_name) / sizeof (char *); |
|
|
849 | assign (name, light_book_name[rndm (nbr)]); |
|
|
850 | } |
|
|
851 | break; |
823 | break; |
852 | } |
824 | } |
853 | |
825 | |
854 | book->name = name; |
826 | book->name = name; |
855 | } |
827 | } |
856 | |
828 | |
857 | /* add_book_author() |
829 | /* add_book_author() |
858 | * A lot like new_text_name above, but instead chooses an author |
830 | * A lot like new_text_name above, but instead chooses an author |
859 | * and sets op->title to that value |
831 | * and sets op->title to that value |
860 | */ |
832 | */ |
861 | |
833 | |
862 | static void |
834 | static void |
863 | add_author (object *op, int msgtype) |
835 | add_author (object *op, int msgtype) |
864 | { |
836 | { |
865 | char title[MAX_BUF], name[MAX_BUF]; |
837 | const char *name; |
866 | int nbr = sizeof (book_author) / sizeof (char *); |
|
|
867 | |
838 | |
868 | if (msgtype < 0 || strlen (op->msg) < 5) |
839 | if (msgtype < 0 || strlen (op->msg) < 5) |
869 | return; |
840 | return; |
870 | |
841 | |
871 | switch (msgtype) |
842 | switch (msgtype) |
872 | { |
843 | { |
873 | case 1: /* monster */ |
844 | case 1: /* monster */ |
874 | nbr = sizeof (mon_author) / sizeof (char *); |
845 | name = mon_author[rndm (array_length (mon_author))]; |
875 | assign (name, mon_author[rndm (nbr)]); |
|
|
876 | break; |
846 | break; |
877 | case 2: /* artifacts */ |
847 | case 2: /* artifacts */ |
878 | nbr = sizeof (art_author) / sizeof (char *); |
848 | name = art_author[rndm (array_length (art_author))]; |
879 | assign (name, art_author[rndm (nbr)]); |
|
|
880 | break; |
849 | break; |
881 | case 3: /* spellpath */ |
850 | case 3: /* spellpath */ |
882 | nbr = sizeof (path_author) / sizeof (char *); |
851 | name = path_author[rndm (array_length (path_author))]; |
883 | assign (name, path_author[rndm (nbr)]); |
|
|
884 | break; |
852 | break; |
885 | case 4: /* alchemy */ |
853 | case 4: /* alchemy */ |
886 | nbr = sizeof (formula_author) / sizeof (char *); |
854 | name = formula_author[rndm (array_length (formula_author))]; |
887 | assign (name, formula_author[rndm (nbr)]); |
|
|
888 | break; |
855 | break; |
889 | case 5: /* gods */ |
856 | case 5: /* gods */ |
890 | nbr = sizeof (gods_author) / sizeof (char *); |
857 | name = gods_author[rndm (array_length (gods_author))]; |
891 | assign (name, gods_author[rndm (nbr)]); |
|
|
892 | break; |
858 | break; |
893 | case 6: /* msg file */ |
859 | case 6: /* msg file */ |
894 | default: |
860 | default: |
895 | assign (name, book_author[rndm (nbr)]); |
861 | name = book_author[rndm (array_length (book_author))]; |
896 | } |
862 | } |
897 | |
863 | |
898 | sprintf (title, "of %s", name); |
864 | op->title = format ("of %s", name); |
899 | op->title = title; |
|
|
900 | } |
865 | } |
901 | |
866 | |
902 | /* unique_book() - check to see if the book title/msg is unique. We |
867 | /* unique_book() - check to see if the book title/msg is unique. We |
903 | * go through the entire list of possibilities each time. If we find |
868 | * go through the entire list of possibilities each time. If we find |
904 | * a match, then unique_book returns true (because inst unique). |
869 | * a match, then unique_book returns true (because inst unique). |
905 | */ |
870 | */ |
906 | |
871 | |
907 | static int |
872 | static int |
… | |
… | |
954 | #endif |
919 | #endif |
955 | |
920 | |
956 | } |
921 | } |
957 | |
922 | |
958 | |
923 | |
959 | /* change_book() - give a new, fancier name to generated |
924 | /* change_book() - give a new, fancier name to generated |
960 | * objects of type BOOK and SPELLBOOK. |
925 | * objects of type BOOK and SPELLBOOK. |
961 | * Aug 96 I changed this so we will attempt to create consistent |
926 | * Aug 96 I changed this so we will attempt to create consistent |
962 | * authour/title and message content for BOOKs. Also, we will |
927 | * authour/title and message content for BOOKs. Also, we will |
963 | * alter books that match archive entries to the archival |
928 | * alter books that match archive entries to the archival |
964 | * levels and architypes. -b.t. |
929 | * levels and architypes. -b.t. |
965 | */ |
930 | */ |
966 | |
931 | |
967 | #define MAX_TITLE_CHECK 20 |
932 | #define MAX_TITLE_CHECK 20 |
968 | |
933 | |
969 | static void |
934 | static void |
… | |
… | |
979 | title *t = NULL; |
944 | title *t = NULL; |
980 | int tries = 0; |
945 | int tries = 0; |
981 | |
946 | |
982 | /* look to see if our msg already been archived. If so, alter |
947 | /* look to see if our msg already been archived. If so, alter |
983 | * the book to match the archival text. If we fail to match, |
948 | * the book to match the archival text. If we fail to match, |
984 | * then we archive the new title/name/msg combo if there is |
949 | * then we archive the new title/name/msg combo if there is |
985 | * room on the titlelist. |
950 | * room on the titlelist. |
986 | */ |
951 | */ |
987 | |
952 | |
988 | if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype))) |
953 | if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype))) |
989 | { |
954 | { |
990 | /* alter book properties */ |
955 | /* alter book properties */ |
991 | if (object *tmpbook = get_archetype (t->archname)) |
956 | if (object *tmpbook = archetype::get (t->archname)) |
992 | { |
957 | { |
993 | tmpbook->msg = book->msg; |
958 | tmpbook->msg = book->msg; |
994 | tmpbook->copy_to (book); |
959 | tmpbook->copy_to (book); |
995 | tmpbook->destroy (); |
960 | tmpbook->destroy (); |
996 | } |
961 | } |
… | |
… | |
1040 | |
1005 | |
1041 | /* Now deal with 2 cases. |
1006 | /* Now deal with 2 cases. |
1042 | * 1)If no space for a new title exists lets just restore |
1007 | * 1)If no space for a new title exists lets just restore |
1043 | * the old book properties. Remember, if the book had |
1008 | * the old book properties. Remember, if the book had |
1044 | * matchd an older entry on the titlelist, we shouldnt |
1009 | * matchd an older entry on the titlelist, we shouldnt |
1045 | * have called this routine in the first place! |
1010 | * have called this routine in the first place! |
1046 | * 2) If we got a unique title, we need to add it to |
1011 | * 2) If we got a unique title, we need to add it to |
1047 | * the list. |
1012 | * the list. |
1048 | */ |
1013 | */ |
1049 | |
1014 | |
1050 | if (tries == MAX_TITLE_CHECK || numb == maxnames) |
1015 | if (tries == MAX_TITLE_CHECK || numb == maxnames) |
… | |
… | |
1054 | #endif |
1019 | #endif |
1055 | /* restore old book properties here */ |
1020 | /* restore old book properties here */ |
1056 | book->title = old_title; |
1021 | book->title = old_title; |
1057 | |
1022 | |
1058 | if (rndm (4)) |
1023 | if (rndm (4)) |
1059 | { |
|
|
1060 | /* Lets give the book a description to individualize it some */ |
1024 | /* Lets give the book a description to individualize it some */ |
1061 | char new_name[MAX_BUF]; |
|
|
1062 | |
|
|
1063 | snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[rndm (nbr)], old_name); |
1025 | book->name = format ("%s %s", book_descrpt[rndm (nbr)], old_name); |
1064 | |
|
|
1065 | book->name = new_name; |
|
|
1066 | } |
|
|
1067 | else |
1026 | else |
1068 | { |
|
|
1069 | book->name = old_name; |
1027 | book->name = old_name; |
1070 | } |
|
|
1071 | } |
1028 | } |
1072 | else if (book->title && strlen (book->msg) > 5) |
1029 | else if (book->title && strlen (book->msg) > 5) |
1073 | { /* archive if long msg texts */ |
1030 | { /* archive if long msg texts */ |
1074 | add_book_to_list (book, msgtype); |
1031 | add_book_to_list (book, msgtype); |
1075 | } |
1032 | } |
… | |
… | |
1092 | |
1049 | |
1093 | /***************************************************************************** |
1050 | /***************************************************************************** |
1094 | * Monster msg generation code. |
1051 | * Monster msg generation code. |
1095 | ****************************************************************************/ |
1052 | ****************************************************************************/ |
1096 | |
1053 | |
1097 | /* get_random_mon() - returns a random monster slected from linked |
1054 | /* get_random_mon() - returns a random monster slected from linked |
1098 | * list of all monsters in the current game. If level is non-zero, |
1055 | * list of all monsters in the current game. If level is non-zero, |
1099 | * then only monsters greater than that level will be returned. |
1056 | * then only monsters greater than that level will be returned. |
1100 | * Changed 971225 to be greater than equal to level passed. Also |
1057 | * Changed 971225 to be greater than equal to level passed. Also |
1101 | * made choosing by level more random. |
1058 | * made choosing by level more random. |
1102 | */ |
1059 | */ |
… | |
… | |
1128 | } |
1085 | } |
1129 | |
1086 | |
1130 | /* Case where we are searching by level. Redone 971225 to be clearer |
1087 | /* Case where we are searching by level. Redone 971225 to be clearer |
1131 | * and more random. Before, it looks like it took a random monster from |
1088 | * and more random. Before, it looks like it took a random monster from |
1132 | * the list, and then returned the first monster after that which was |
1089 | * the list, and then returned the first monster after that which was |
1133 | * appropriate level. This wasn't very random because if you had a |
1090 | * appropriate level. This wasn't very random because if you had a |
1134 | * bunch of low level monsters and then a high level one, if the random |
1091 | * bunch of low level monsters and then a high level one, if the random |
1135 | * determine took one of the low level ones, it would just forward to the |
1092 | * determine took one of the low level ones, it would just forward to the |
1136 | * high level one and return that. Thus, monsters that immediatly followed |
1093 | * high level one and return that. Thus, monsters that immediatly followed |
1137 | * a bunch of low level monsters would be more heavily returned. It also |
1094 | * a bunch of low level monsters would be more heavily returned. It also |
1138 | * means some of the dragons would be poorly represented, since they |
1095 | * means some of the dragons would be poorly represented, since they |
… | |
… | |
1201 | else |
1158 | else |
1202 | return first_mon_info->ob; |
1159 | return first_mon_info->ob; |
1203 | |
1160 | |
1204 | } |
1161 | } |
1205 | |
1162 | |
1206 | /* mon_info_msg() - generate a message detailing the properties |
1163 | /* mon_info_msg() - generate a message detailing the properties |
1207 | * of a randomly selected monster. |
1164 | * of a randomly selected monster. |
1208 | */ |
1165 | */ |
1209 | static const char * |
1166 | static const char * |
1210 | mon_info_msg (int level) |
1167 | mon_info_msg (int level) |
1211 | { |
1168 | { |
1212 | static dynbuf_text buf; buf.clear (); |
1169 | static dynbuf_text buf; buf.clear (); |
1213 | |
1170 | |
1214 | /*preamble */ |
1171 | /*preamble */ |
1215 | buf << "This beastiary contains:\n"; |
1172 | buf << "This beastiary contains:\n"; |
1216 | |
1173 | |
1217 | /* lets print info on as many monsters as will fit in our |
1174 | /* lets print info on as many monsters as will fit in our |
1218 | * document. |
1175 | * document. |
1219 | * 8-96 Had to change this a bit, otherwise there would |
1176 | * 8-96 Had to change this a bit, otherwise there would |
1220 | * have been an impossibly large number of combinations |
1177 | * have been an impossibly large number of combinations |
1221 | * of text! (and flood out the available number of titles |
1178 | * of text! (and flood out the available number of titles |
1222 | * in the archive in a snap!) -b.t. |
1179 | * in the archive in a snap!) -b.t. |
1223 | */ |
1180 | */ |
1224 | object *tmp = get_random_mon (level * 3); |
1181 | object *tmp = get_random_mon (level * 3); |
1225 | while (tmp && buf.size () < BOOK_BUF) |
1182 | while (tmp && buf.size () < BOOK_BUF) |
1226 | { |
1183 | { |
1227 | /* monster description */ |
1184 | /* monster description */ |
… | |
… | |
1265 | * for that type exists! |
1222 | * for that type exists! |
1266 | */ |
1223 | */ |
1267 | i = 0; |
1224 | i = 0; |
1268 | do |
1225 | do |
1269 | { |
1226 | { |
1270 | index = rndm (sizeof (art_name_array) / sizeof (arttypename)); |
1227 | index = rndm (array_length (art_name_array)); |
1271 | type = art_name_array[index].type; |
1228 | type = art_name_array[index].type; |
1272 | al = find_artifactlist (type); |
1229 | al = find_artifactlist (type); |
1273 | i++; |
1230 | i++; |
1274 | } |
1231 | } |
1275 | while ((al == NULL) && (i < 10)); |
1232 | while ((al == NULL) && (i < 10)); |
… | |
… | |
1295 | buf.printf ("Herein %s detailed %s...\n", |
1252 | buf.printf ("Herein %s detailed %s...\n", |
1296 | book_entries > 1 ? "are" : "is", |
1253 | book_entries > 1 ? "are" : "is", |
1297 | book_entries > 1 ? "some artifacts" : "an artifact"); |
1254 | book_entries > 1 ? "some artifacts" : "an artifact"); |
1298 | |
1255 | |
1299 | /* artifact msg attributes loop. Lets keep adding entries to the 'book' |
1256 | /* artifact msg attributes loop. Lets keep adding entries to the 'book' |
1300 | * as long as we have space up to the allowed max # (book_entires) |
1257 | * as long as we have space up to the allowed max # (book_entires) |
1301 | */ |
1258 | */ |
1302 | while (book_entries > 0 && buf.size () < BOOK_BUF) |
1259 | while (book_entries > 0 && buf.size () < BOOK_BUF) |
1303 | { |
1260 | { |
1304 | |
1261 | |
1305 | if (!art) |
1262 | if (!art) |
… | |
… | |
1366 | /***************************************************************************** |
1323 | /***************************************************************************** |
1367 | * Spellpath message generation |
1324 | * Spellpath message generation |
1368 | *****************************************************************************/ |
1325 | *****************************************************************************/ |
1369 | |
1326 | |
1370 | /* spellpath_msg() - generate a message detailing the member |
1327 | /* spellpath_msg() - generate a message detailing the member |
1371 | * incantations/prayers (and some of their properties) belonging to |
1328 | * incantations/prayers (and some of their properties) belonging to |
1372 | * a given spellpath. |
1329 | * a given spellpath. |
1373 | */ |
1330 | */ |
1374 | static char * |
1331 | static char * |
1375 | spellpath_msg (int level) |
1332 | spellpath_msg (int level) |
1376 | { |
1333 | { |
1377 | static dynbuf_text buf; buf.clear (); |
1334 | static dynbuf_text buf; buf.clear (); |
1378 | |
1335 | |
1379 | static char retbuf[BOOK_BUF]; |
|
|
1380 | char tmpbuf[BOOK_BUF]; |
|
|
1381 | int path = rndm (NRSPELLPATHS), prayers = rndm (2); |
1336 | int path = rndm (NRSPELLPATHS), prayers = rndm (2); |
1382 | uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path]; |
1337 | uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path]; |
1383 | archetype *at; |
1338 | archetype *at; |
1384 | |
1339 | |
1385 | /* Preamble */ |
1340 | /* Preamble */ |
… | |
… | |
1427 | int chance; |
1382 | int chance; |
1428 | |
1383 | |
1429 | static dynbuf_text buf; buf.clear (); |
1384 | static dynbuf_text buf; buf.clear (); |
1430 | |
1385 | |
1431 | /* the higher the book level, the more complex (ie number of |
1386 | /* the higher the book level, the more complex (ie number of |
1432 | * ingredients) the formula can be. |
1387 | * ingredients) the formula can be. |
1433 | */ |
1388 | */ |
1434 | fl = get_formulalist (rndm (level) / 3 + 1); |
1389 | fl = get_formulalist (rndm (level) / 3 + 1); |
1435 | |
1390 | |
1436 | if (!fl) |
1391 | if (!fl) |
1437 | fl = get_formulalist (1); /* safety */ |
1392 | fl = get_formulalist (1); /* safety */ |
… | |
… | |
1595 | int i; |
1550 | int i; |
1596 | |
1551 | |
1597 | if (enemy && !(god->path_denied & PATH_TURNING)) |
1552 | if (enemy && !(god->path_denied & PATH_TURNING)) |
1598 | if ((i = nstrtok (enemy, ",")) > 0) |
1553 | if ((i = nstrtok (enemy, ",")) > 0) |
1599 | { |
1554 | { |
1600 | char tmpbuf[MAX_BUF]; |
|
|
1601 | |
|
|
1602 | buf << "The holy words of " << name |
1555 | buf << "The holy words of " << name |
1603 | << " have the power to slay creatures belonging to the "; |
1556 | << " have the power to slay creatures belonging to the "; |
1604 | |
1557 | |
1605 | if (i > 1) |
1558 | if (i > 1) |
1606 | buf << "following races:" << strtoktolin (enemy, ","); |
1559 | buf << "following races:" << strtoktolin (enemy, ","); |
… | |
… | |
1682 | { /* spell paths */ |
1635 | { /* spell paths */ |
1683 | //TODO: |
1636 | //TODO: |
1684 | int has_effect = 0, tmpvar; |
1637 | int has_effect = 0, tmpvar; |
1685 | char tmpbuf[MAX_BUF]; |
1638 | char tmpbuf[MAX_BUF]; |
1686 | |
1639 | |
1687 | sprintf (tmpbuf, "\n"); |
|
|
1688 | sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name); |
1640 | sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name); |
1689 | strcat (tmpbuf, "are mystically transformed. Effects of this include:\n"); |
1641 | strcat (tmpbuf, "are mystically transformed. Effects of this include:\n"); |
1690 | |
1642 | |
1691 | if ((tmpvar = god->path_attuned)) |
1643 | if ((tmpvar = god->path_attuned)) |
1692 | { |
1644 | { |
… | |
… | |
1720 | buf << "[Unfortunately the rest of the information is hopelessly garbled!]"; |
1672 | buf << "[Unfortunately the rest of the information is hopelessly garbled!]"; |
1721 | |
1673 | |
1722 | return buf; |
1674 | return buf; |
1723 | } |
1675 | } |
1724 | |
1676 | |
1725 | /* tailor_readable_ob()- The main routine. This chooses a random |
1677 | /* tailor_readable_ob()- The main routine. This chooses a random |
1726 | * message to put in given readable object (type==BOOK) which will |
1678 | * message to put in given readable object (type==BOOK) which will |
1727 | * be referred hereafter as a 'book'. We use the book level to de- |
1679 | * be referred hereafter as a 'book'. We use the book level to de- |
1728 | * termine the value of the information we will insert. Higher |
1680 | * termine the value of the information we will insert. Higher |
1729 | * values mean the book will (generally) have better/more info. |
1681 | * values mean the book will (generally) have better/more info. |
1730 | * See individual cases as to how this will be utilized. |
1682 | * See individual cases as to how this will be utilized. |
1731 | * "Book" name/content length are based on the weight of the |
1683 | * "Book" name/content length are based on the weight of the |
1732 | * document. If the value of msg_type is negative, we will randomly |
1684 | * document. If the value of msg_type is negative, we will randomly |
1733 | * choose the kind of message to generate. |
1685 | * choose the kind of message to generate. |
1734 | * -b.t. thomas@astro.psu.edu |
1686 | * -b.t. thomas@astro.psu.edu |
1735 | * |
1687 | * |
1736 | * book is the object we are creating into. |
1688 | * book is the object we are creating into. |
1737 | * If msg_type is a positive value, we use that to determine the |
1689 | * If msg_type is a positive value, we use that to determine the |
1738 | * message type - otherwise a random value is used. |
1690 | * message type - otherwise a random value is used. |