--- deliantra/server/common/readable.C 2006/09/14 22:34:00 1.9 +++ deliantra/server/common/readable.C 2012/11/12 03:14:32 1.66 @@ -1,26 +1,26 @@ /* - CrossFire, A Multiplayer game for X-windows - - Copyright (C) 2002 Mark Wedel & Crossfire Development Team - Copyright (C) 1992 Frank Tore Johansen - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - - The authors can be reached via e-mail at -*/ - + * This file is part of Deliantra, the Roguelike Realtime MMORPG. + * + * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 Marc Alexander Lehmann / Robin Redeker / the Deliantra team + * Copyright (©) 2002 Mark Wedel & Crossfire Development Team + * Copyright (©) 1992 Frank Tore Johansen + * + * Deliantra is free software: you can redistribute it and/or modify it under + * the terms of the Affero GNU General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the Affero GNU General Public License + * and the GNU General Public License along with this program. If not, see + * . + * + * The authors can be reached via e-mail to + */ /* This file contains code relevant to the BOOKS hack -- designed * to allow randomly occuring messages in non-magical texts. @@ -33,7 +33,6 @@ #include #include - /* Define this if you want to archive book titles by contents. * This option should enforce UNIQUE combinations of titles,authors and * msg contents during and *between* game sessions. @@ -111,20 +110,9 @@ static int nrofmon = 0, need_to_write_bookarchive = 0; - -/* this is needed to keep track of status of initialization - * of the message file */ -static int nrofmsg = 0; - -/* first_msg is the started of the linked list of messages as read from - * the messages file - */ -static linked_char *first_msg = NULL; - /* * Spellpath information */ - static uint32 spellpathdef[NRSPELLPATHS] = { PATH_PROT, PATH_FIRE, @@ -189,7 +177,7 @@ {"Boots", BOOTS}, {"Cloak", CLOAK}, {"Gloves", GLOVES}, - {"Gridle", GIRDLE}, + {"Girdle", GIRDLE}, {"Ring", RING}, {"Horn", HORN}, {"Missile Weapon", BOW}, @@ -415,7 +403,7 @@ "cryptic", "cryptical", "dusty", - "hiearchical", + "hierarchical", "grizzled", "gold-guilt", "great", @@ -437,70 +425,70 @@ * subtype paramater in arch files! */ static readable_message_type readable_message_types[] = { - /*subtype 0 */ {0, 0}, + /*subtype 0 */ {0, 0, "info"}, /* book messages subtypes */ - /*subtype 1 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_2}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_1}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_2}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_1}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_2}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_EVOKER}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PRAYER}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PYRO}, - /*subtype 10 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER}, - {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SUMMONER}, + /*subtype 1 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_1, "readable-book-clasp-1"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_CLASP_2, "readable-book-clasp-2"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_1, "readable-book-elegant-1"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_ELEGANT_2, "readable-book-elegant-2"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_1, "readable-book-quarto-1"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_QUARTO_2, "readable-book-quarto-2"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_EVOKER, "readable-book-spell-evocation"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PRAYER, "readable-book-spell-praying"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_PYRO, "readable-book-spell-pyromancy"}, + /*subtype 10 */ {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SORCERER, "readable-book-spell-sorcery"}, + {MSG_TYPE_BOOK, MSG_TYPE_BOOK_SPELL_SUMMONER, "readable-book-spell-summoning"}, /* card messages subtypes */ - {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_1}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_2}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_3}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_1}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_2}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_3}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_1}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_2}, - /*subtype 20 */ {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_1}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_2}, - {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_3}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_1, "readable-card-simple-1"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_2, "readable-card-simple-2"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_SIMPLE_3, "readable-card-simple-3"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_1, "readable-card-elegant-1"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_2, "readable-card-elegant-2"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_ELEGANT_3, "readable-card-elegant-3"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_1, "readable-card-strange-1"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_2, "readable-card-strange-2"}, + /*subtype 20 */ {MSG_TYPE_CARD, MSG_TYPE_CARD_STRANGE_3, "readable-card-strange-3"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_1, "readable-card-money-1"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_2, "readable-card-money-2"}, + {MSG_TYPE_CARD, MSG_TYPE_CARD_MONEY_3, "readable-card-money-3"}, /* Paper messages subtypes */ - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_1}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_3}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_1}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_1}, - /*subtype 30 */ {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_1}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_1}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_1}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_2}, - {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_MAGIC}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_1, "readable-paper-note-1"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_2, "readable-paper-note-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_NOTE_3, "readable-paper-note-3"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_1, "readable-paper-letter-old-1"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_OLD_2, "readable-paper-letter-old-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_1, "readable-paper-letter-new-1"}, + /*subtype 30 */ {MSG_TYPE_PAPER, MSG_TYPE_PAPER_LETTER_NEW_2, "readable-paper-letter-new-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_1, "readable-paper-envelope-1"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_ENVELOPE_2, "readable-paper-envelope-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_1, "readable-paper-scroll-old-1"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_OLD_2, "readable-paper-scroll-old-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_1, "readable-paper-scroll-new-1"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_NEW_2, "readable-paper-scroll-new-2"}, + {MSG_TYPE_PAPER, MSG_TYPE_PAPER_SCROLL_MAGIC, "readable-paper-scroll-magic"}, /* road signs messages subtypes */ - {MSG_TYPE_SIGN, MSG_TYPE_SIGN_BASIC}, - {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_LEFT}, - /*subtype 40 */ {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT}, - {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_BOTH}, + {MSG_TYPE_SIGN, MSG_TYPE_SIGN_BASIC, "readable-sign-basic"}, + {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_LEFT, "readable-sign-dir-left"}, + /*subtype 40 */ {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_RIGHT, "readable-sign-dir-right"}, + {MSG_TYPE_SIGN, MSG_TYPE_SIGN_DIR_BOTH, "readable-sign-dir-both"}, /* stones and monument messages */ - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_1}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_2}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_3}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_1}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_2}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_3}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_1}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_2}, - /*subtype 50 */ {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_3}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_1}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_2}, - {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_3} + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_1, "readable-monument-stone-1"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_2, "readable-monument-stone-2"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STONE_3, "readable-monument-stone-3"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_1, "readable-monument-statue-1"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_2, "readable-monument-statue-2"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_STATUE_3, "readable-monument-statue-3"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_1, "readable-monument-gravestone-1"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_2, "readable-monument-gravestone-2"}, + /*subtype 50 */ {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_GRAVESTONE_3, "readable-monument-gravestone-3"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_1, "readable-monument-wall-1"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_2, "readable-monument-wall-2"}, + {MSG_TYPE_MONUMENT, MSG_TYPE_MONUMENT_WALL_3, "readable-monument-wall-3"} }; -int last_readable_subtype = sizeof (readable_message_types) / sizeof (readable_message_type); +static int last_readable_subtype = sizeof (readable_message_types) / sizeof (readable_message_type); static int max_titles[6] = { ((sizeof (light_book_name) / sizeof (char *)) + (sizeof (heavy_book_name) / sizeof (char *))) * (sizeof (book_author) / sizeof (char *)), @@ -518,7 +506,7 @@ *****************************************************************************/ static titlelist * -get_empty_booklist (void) +get_empty_booklist () { titlelist *bl = new titlelist; @@ -529,7 +517,7 @@ } static title * -get_empty_book (void) +get_empty_book () { title *t = new title; @@ -548,6 +536,9 @@ static titlelist * get_titlelist (int i) { + if (!booklist) + booklist = get_empty_booklist (); + titlelist *tl = booklist; int number = i; @@ -560,7 +551,7 @@ tl->next = get_empty_booklist (); tl = tl->next; - number--; + --number; } return tl; @@ -572,8 +563,7 @@ /* nstrtok() - simple routine to return the number of list * items in buf1 as separated by the value of buf2 */ - -int +static int nstrtok (const char *buf1, const char *buf2) { char *tbuf, sbuf[12], buf[MAX_BUF]; @@ -581,8 +571,10 @@ if (!buf1 || !buf2) return 0; - sprintf (buf, "%s", buf1); - sprintf (sbuf, "%s", buf2); + + strcpy (buf, buf1); + strcpy (sbuf, buf2); + tbuf = strtok (buf, sbuf); while (tbuf) { @@ -596,8 +588,7 @@ * a list of strings delimited by buf2. Then returns a comma * separated string w/ decent punctuation. */ - -char * +static char * strtoktolin (const char *buf1, const char *buf2) { int maxi, i = nstrtok (buf1, buf2); @@ -612,6 +603,7 @@ while (tbuf && i > 0) { strcat (rbuf, tbuf); + i--; if (i == 1 && maxi > 1) strcat (rbuf, " and "); @@ -619,246 +611,138 @@ strcat (rbuf, ", "); else strcat (rbuf, "."); + tbuf = strtok (NULL, sbuf); } - return (char *) rbuf; -} - -int -book_overflow (const char *buf1, const char *buf2, int booksize) -{ - - if (buf_overflow (buf1, buf2, BOOK_BUF - 2) /* 2 less so always room for trailing \n */ - || buf_overflow (buf1, buf2, booksize)) - return 1; - return 0; - + return rbuf; } /***************************************************************************** * - * Start of initialization related functions. + * Start of initialisation related functions. * ****************************************************************************/ -/* init_msgfile() - if not called before, initialize the info list - * reads the messages file into the list pointed to by first_msg -*/ - -static void -init_msgfile (void) -{ - FILE *fp; - char buf[MAX_BUF], msgbuf[HUGE_BUF], fname[MAX_BUF], *cp; - int comp; - static int did_init_msgfile; - - if (did_init_msgfile) - return; - did_init_msgfile = 1; - - sprintf (fname, "%s/messages", settings.datadir); - LOG (llevDebug, "Reading messages from %s...", fname); - - if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL) - { - linked_char *tmp = NULL; - - while (fgets (buf, MAX_BUF, fp) != NULL) - { - if (*buf == '#') - continue; - if ((cp = strchr (buf, '\n')) != NULL) - *cp = '\0'; - cp = buf; - while (*cp == ' ') /* Skip blanks */ - cp++; - if (!strncmp (cp, "ENDMSG", 6)) - { - if (strlen (msgbuf) > BOOK_BUF) - { - LOG (llevDebug, "Warning: this string exceeded max book buf size:"); - LOG (llevDebug, " %s", msgbuf); - } - tmp->name = msgbuf; - tmp->next = first_msg; - first_msg = tmp; - nrofmsg++; - continue; - } - else if (!strncmp (cp, "MSG", 3)) - { - tmp = new linked_char; - - strcpy (msgbuf, " "); /* reset msgbuf for new message */ - continue; - } - else if (!buf_overflow (msgbuf, cp, HUGE_BUF - 1)) - { - strcat (msgbuf, cp); - strcat (msgbuf, "\n"); - } - } - close_and_delete (fp, comp); - } - -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "\ninit_info_listfile() got %d messages.\n", nrofmsg); -#endif - LOG (llevDebug, "done.\n"); -} - - -/* init_book_archive() - if not called before, initialize the info list +/* init_book_archive() - if not called before, initialise the info list * This reads in the bookarch file into memory. bookarch is the file * created and updated across multiple runs of the program. */ - static void -init_book_archive (void) +init_book_archive () { - FILE *fp; - int comp, nroftitle = 0; - char buf[MAX_BUF], fname[MAX_BUF], *cp; - title *book = NULL; + int nroftitle = 0; titlelist *bl = get_empty_booklist (); - static int did_init_barch; - if (did_init_barch) - return; + object_thawer thawer (settings.localdir, "bookarch"); - did_init_barch = 1; + if (!thawer) + { + LOG (llevDebug, "could not read bookarch file\n"); + return; + } - if (!booklist) - booklist = bl; + while (thawer.kw) + { + if (thawer.kw != KW_title) + if (!thawer.parse_error ("bookarch file")) + break; - sprintf (fname, "%s/bookarch", settings.localdir); - LOG (llevDebug, " Reading bookarch from %s...\n", fname); + title *book = get_empty_book (); /* init new book entry */ + thawer.get (book->name); - if ((fp = open_and_uncompress (fname, 0, &comp)) != NULL) - { - int value, type = 0; - size_t i; + int type = -1; - while (fgets (buf, MAX_BUF, fp) != NULL) + for (;;) { - if (*buf == '#') - continue; - if ((cp = strchr (buf, '\n')) != NULL) - *cp = '\0'; - cp = buf; - while (*cp == ' ') /* Skip blanks */ - cp++; - if (!strncmp (cp, "title", 4)) - { - book = get_empty_book (); /* init new book entry */ - book->name = strchr (cp, ' ') + 1; - type = -1; - nroftitle++; - continue; - } - if (!strncmp (cp, "authour", 4)) - { - book->authour = strchr (cp, ' ') + 1; - } - if (!strncmp (cp, "arch", 4)) - { - book->archname = strchr (cp, ' ') + 1; - } - else if (sscanf (cp, "level %d", &value)) - { - book->level = (uint16) value; - } - else if (sscanf (cp, "type %d", &value)) - { - type = (uint16) value; - } - else if (sscanf (cp, "size %d", &value)) - { - book->size = (uint16) value; - } - else if (sscanf (cp, "index %d", &value)) + thawer.next (); + + switch (thawer.kw) { - book->msg_index = (uint16) value; - } - else if (!strncmp (cp, "end", 3)) - { /* link it */ - bl = get_titlelist (type); - book->next = bl->first_book; - bl->first_book = book; - bl->number++; + case KW_type: thawer.get (type ); break; + case KW_authour: thawer.get (book->authour ); break; + case KW_arch: thawer.get (book->archname ); break; + case KW_level: thawer.get (book->level ); break; + case KW_size: thawer.get (book->size ); break; + case KW_index: thawer.get (book->msg_index); break; + + case KW_end: + /* link it */ + bl = get_titlelist (type); + book->next = bl->first_book; + bl->first_book = book; + bl->number++; + ++nroftitle; + goto book_done; + + default: + delete book; + goto book_done; } } - LOG (llevDebug, " book archives(used/avail): "); - for (bl = booklist, i = 0; bl != NULL && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++) - { - LOG (llevDebug, "(%d/%d)", bl->number, max_titles[i]); - } - LOG (llevDebug, "\n"); - close_and_delete (fp, comp); + +book_done: + thawer.next (); } -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "\n init_book_archive() got %d titles.\n", nroftitle); -#endif - LOG (llevDebug, " done.\n"); + LOG (llevDebug, "book archives(used/avail): \n"); + int i; + for (bl = booklist, i = 0; bl && i < sizeof (max_titles) / sizeof (*max_titles); bl = bl->next, i++) + LOG (llevDebug, " (%d/%d)\n", bl->number, max_titles[i]); + + LOG (llevDebug, "init_book_archive() got %d titles.\n", nroftitle); } /* init_mon_info() - creates the linked list of pointers to * monster archetype objects if not called previously */ - static void -init_mon_info (void) +init_mon_info () { archetype *at; static int did_init_mon_info = 0; if (did_init_mon_info) return; + did_init_mon_info = 1; + for_all_archetypes (at) + if (at->flag [FLAG_MONSTER] + && at->is_head () + && (!at->flag [FLAG_CHANGING] || at->flag [FLAG_UNAGGRESSIVE])) + { + objectlink *mon = new objectlink; + + mon->ob = at; + mon->next = first_mon_info; + first_mon_info = mon; + nrofmon++; + } - for (at = first_archetype; at != NULL; at = at->next) - { - if (QUERY_FLAG (&at->clone, FLAG_MONSTER) && (!QUERY_FLAG (&at->clone, FLAG_CHANGING) || QUERY_FLAG (&at->clone, FLAG_UNAGGRESSIVE))) - { - objectlink *mon = (objectlink *) malloc (sizeof (objectlink)); - - mon->ob = &at->clone; - mon->id = nrofmon; - mon->next = first_mon_info; - first_mon_info = mon; - nrofmon++; - } - } LOG (llevDebug, "init_mon_info() got %d monsters\n", nrofmon); } - -/* init_readable() - initialize linked lists utilized by +/* init_readable() - initialise linked lists utilized by * message functions in tailor_readable_ob() * - * This is the function called by the main routine to initialize + * This is the function called by the main routine to initialise * all the readable information. */ - void -init_readable (void) +init_readable () { static int did_this; if (did_this) return; + did_this = 1; - LOG (llevDebug, "Initializing reading data..."); - init_msgfile (); + LOG (llevDebug, "Initialising reading data...\n"); init_book_archive (); init_mon_info (); LOG (llevDebug, " Done\n"); - } /***************************************************************************** @@ -868,11 +752,9 @@ * *****************************************************************************/ - /* find_title() - Search the titlelist (based on msgtype) to see if * book matches something already there. IF so, return that title. */ - static title * find_title (const object *book, int msgtype) { @@ -895,7 +777,7 @@ #ifdef ARCHIVE_DEBUG if (t) - LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, t->name, t->authour, t->msg_index); + LOG (llevDebug, "Found title match (list %d): %s %s (%d)\n", msgtype, &t->name, &t->authour, t->msg_index); #endif return t; @@ -907,57 +789,43 @@ * this sets book book->name based on msgtype given. What name * is given is based on various criteria */ - static void new_text_name (object *book, int msgtype) { - int nbr; - char name[MAX_BUF]; + const char *name; if (book->type != BOOK) return; switch (msgtype) { - case 1: /*monster */ - nbr = sizeof (mon_book_name) / sizeof (char *); - strcpy (name, mon_book_name[RANDOM () % nbr]); - break; - case 2: /*artifact */ - nbr = sizeof (art_book_name) / sizeof (char *); - strcpy (name, art_book_name[RANDOM () % nbr]); - break; - case 3: /*spellpath */ - nbr = sizeof (path_book_name) / sizeof (char *); - strcpy (name, path_book_name[RANDOM () % nbr]); - break; - case 4: /*alchemy */ - nbr = sizeof (formula_book_name) / sizeof (char *); - strcpy (name, formula_book_name[RANDOM () % nbr]); - break; - case 5: /*gods */ - nbr = sizeof (gods_book_name) / sizeof (char *); - strcpy (name, gods_book_name[RANDOM () % nbr]); - break; - case 6: /*msg file */ - default: - if (book->weight > 2000) - { /* based on weight */ - nbr = sizeof (heavy_book_name) / sizeof (char *); - strcpy (name, heavy_book_name[RANDOM () % nbr]); - } - else if (book->weight < 2001) - { - nbr = sizeof (light_book_name) / sizeof (char *); - strcpy (name, light_book_name[RANDOM () % nbr]); - } - break; + case 1: /*monster */ + name = mon_book_name[rndm (array_length (mon_book_name))]; + break; + case 2: /*artifact */ + name = art_book_name[rndm (array_length (art_book_name))]; + break; + case 3: /*spellpath */ + name = path_book_name[rndm (array_length (path_book_name))]; + break; + case 4: /*alchemy */ + name = formula_book_name[rndm (array_length (formula_book_name))]; + break; + case 5: /*gods */ + name = gods_book_name[rndm (array_length (gods_book_name))]; + break; + case 6: /*msg file */ + default: + name = book->weight > 2000 /* based on weight */ + ? heavy_book_name [rndm (array_length (heavy_book_name))] + : light_book_name [rndm (array_length (light_book_name))]; + break; } book->name = name; } -/* add_book_author() +/* add_book_author() * A lot like new_text_name above, but instead chooses an author * and sets op->title to that value */ @@ -965,41 +833,34 @@ static void add_author (object *op, int msgtype) { - char title[MAX_BUF], name[MAX_BUF]; - int nbr = sizeof (book_author) / sizeof (char *); + const char *name; if (msgtype < 0 || strlen (op->msg) < 5) return; switch (msgtype) { - case 1: /* monster */ - nbr = sizeof (mon_author) / sizeof (char *); - strcpy (name, mon_author[RANDOM () % nbr]); - break; - case 2: /* artifacts */ - nbr = sizeof (art_author) / sizeof (char *); - strcpy (name, art_author[RANDOM () % nbr]); - break; - case 3: /* spellpath */ - nbr = sizeof (path_author) / sizeof (char *); - strcpy (name, path_author[RANDOM () % nbr]); - break; - case 4: /* alchemy */ - nbr = sizeof (formula_author) / sizeof (char *); - strcpy (name, formula_author[RANDOM () % nbr]); - break; - case 5: /* gods */ - nbr = sizeof (gods_author) / sizeof (char *); - strcpy (name, gods_author[RANDOM () % nbr]); - break; - case 6: /* msg file */ - default: - strcpy (name, book_author[RANDOM () % nbr]); + case 1: /* monster */ + name = mon_author[rndm (array_length (mon_author))]; + break; + case 2: /* artifacts */ + name = art_author[rndm (array_length (art_author))]; + break; + case 3: /* spellpath */ + name = path_author[rndm (array_length (path_author))]; + break; + case 4: /* alchemy */ + name = formula_author[rndm (array_length (formula_author))]; + break; + case 5: /* gods */ + name = gods_author[rndm (array_length (gods_author))]; + break; + case 6: /* msg file */ + default: + name = book_author[rndm (array_length (book_author))]; } - sprintf (title, "of %s", name); - op->title = title; + op->title = format ("of %s", name); } /* unique_book() - check to see if the book title/msg is unique. We @@ -1010,19 +871,16 @@ static int unique_book (const object *book, int msgtype) { - title *test; - if (!booklist) return 1; /* No archival entries! Must be unique! */ /* Go through the booklist. If the author and name match, not unique so * return 0. */ - for (test = get_titlelist (msgtype)->first_book; test; test = test->next) - { - if (!strcmp (test->name, book->name) && !strcmp (book->title, test->authour)) - return 0; - } + for (title *test = get_titlelist (msgtype)->first_book; test; test = test->next) + if (test->name == book->name && book->title == test->authour) + return 0; + return 1; } @@ -1045,7 +903,7 @@ t->authour = book->title; t->size = strlen (book->msg); t->msg_index = strtoint (book->msg); - t->archname = book->arch->name; + t->archname = book->arch->archname; t->level = book->level; t->next = tl->first_book; @@ -1056,7 +914,7 @@ need_to_write_bookarchive = 1; #ifdef ARCHIVE_DEBUG - LOG (llevDebug, "Archiving new title: %s %s (%d)\n", book->name, book->title, msgtype); + LOG (llevDebug, "Archiving new title: %s %s (%d)\n", &book->name, &book->title, msgtype); #endif } @@ -1072,123 +930,112 @@ #define MAX_TITLE_CHECK 20 -void +static void change_book (object *book, int msgtype) { int nbr = sizeof (book_descrpt) / sizeof (char *); switch (book->type) { - case BOOK: - { - titlelist *tl = get_titlelist (msgtype); - title *t = NULL; - int tries = 0; - - /* look to see if our msg already been archived. If so, alter - * the book to match the archival text. If we fail to match, - * then we archive the new title/name/msg combo if there is - * room on the titlelist. - */ - - if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype))) - { - object *tmpbook; + case BOOK: + { + titlelist *tl = get_titlelist (msgtype); + title *t = NULL; + int tries = 0; + + /* look to see if our msg already been archived. If so, alter + * the book to match the archival text. If we fail to match, + * then we archive the new title/name/msg combo if there is + * room on the titlelist. + */ - /* alter book properties */ - if ((tmpbook = get_archetype (t->archname)) != NULL) - { - tmpbook->msg = book->msg; - copy_object (tmpbook, book); - free_object (tmpbook); - } + if ((strlen (book->msg) > 5) && (t = find_title (book, msgtype))) + { + /* alter book properties */ + if (object *tmpbook = archetype::get (t->archname)) + { + tmpbook->msg = book->msg; + tmpbook->copy_to (book); + tmpbook->destroy (); + } - book->title = t->authour; - book->name = t->name; - book->level = t->level; - } - /* Don't have any default title, so lets make up a new one */ - else - { - int numb, maxnames = max_titles[msgtype]; - const char *old_title; - const char *old_name; - - old_title = book->title; - old_name = book->name; - - /* some pre-generated books have title already set (from - * maps), also don't bother looking for unique title if - * we already used up all the available names! */ + book->title = t->authour; + book->name = t->name; + book->level = t->level; + } + /* Don't have any default title, so lets make up a new one */ + else + { + int numb, maxnames = max_titles[msgtype]; + const char *old_title; + const char *old_name; + + old_title = book->title; + old_name = book->name; + + /* some pre-generated books have title already set (from + * maps), also don't bother looking for unique title if + * we already used up all the available names! */ - if (!tl) - { - LOG (llevError, "change_book_name(): can't find title list\n"); - numb = 0; - } - else - numb = tl->number; + if (!tl) + { + LOG (llevError, "change_book_name(): can't find title list\n"); + numb = 0; + } + else + numb = tl->number; - if (numb == maxnames) - { + if (numb == maxnames) + { #ifdef ARCHIVE_DEBUG - LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames); + LOG (llevDebug, "titles for list %d full (%d possible).\n", msgtype, maxnames); #endif - break; + } + /* shouldnt change map-maker books */ + else if (!book->title) + do + { + /* random book name */ + new_text_name (book, msgtype); + add_author (book, msgtype); /* random author */ + tries++; } - /* shouldnt change map-maker books */ - else if (!book->title) - do - { - /* random book name */ - new_text_name (book, msgtype); - add_author (book, msgtype); /* random author */ - tries++; - } - while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK); - - /* Now deal with 2 cases. - * 1)If no space for a new title exists lets just restore - * the old book properties. Remember, if the book had - * matchd an older entry on the titlelist, we shouldnt - * have called this routine in the first place! - * 2) If we got a unique title, we need to add it to - * the list. - */ + while (!unique_book (book, msgtype) && tries < MAX_TITLE_CHECK); - if (tries == MAX_TITLE_CHECK || numb == maxnames) - { /* got to check maxnames again */ + /* Now deal with 2 cases. + * 1)If no space for a new title exists lets just restore + * the old book properties. Remember, if the book had + * matchd an older entry on the titlelist, we shouldnt + * have called this routine in the first place! + * 2) If we got a unique title, we need to add it to + * the list. + */ + + if (tries == MAX_TITLE_CHECK || numb == maxnames) + { /* got to check maxnames again */ #ifdef ARCHIVE_DEBUG - LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", book->name, book->title, numb, maxnames); + LOG (llevDebug, "Failed to obtain unique title for %s %s (names:%d/%d)\n", &book->name, &book->title, numb, maxnames); #endif - /* restore old book properties here */ - book->title = old_title; + /* restore old book properties here */ + book->title = old_title; - if (RANDOM () % 4) - { - /* Lets give the book a description to individualize it some */ - char new_name[MAX_BUF]; - - snprintf (new_name, MAX_BUF, "%s %s", book_descrpt[RANDOM () % nbr], old_name); - - book->name = new_name; - } - else - { - book->name = old_name; - } - } - else if (book->title && strlen (book->msg) > 5) - { /* archive if long msg texts */ - add_book_to_list (book, msgtype); - } - } - break; - } + if (rndm (4)) + /* Lets give the book a description to individualize it some */ + book->name = format ("%s %s", book_descrpt[rndm (nbr)], old_name); + else + book->name = old_name; + } + else if (book->title && strlen (book->msg) > 5) + { /* archive if long msg texts */ + add_book_to_list (book, msgtype); + } + } + break; + } - default: - LOG (llevError, "change_book_name() called w/ illegal obj type.\n"); - return; + default: + LOG (llevError, "change_book_name() called w/ illegal obj type.\n"); + return; } } @@ -1209,7 +1056,6 @@ * Changed 971225 to be greater than equal to level passed. Also * made choosing by level more random. */ - object * get_random_mon (int level) { @@ -1223,7 +1069,7 @@ if (!level) { /* lets get a random monster from the mon_info linked list */ - monnr = RANDOM () % nrofmon; + monnr = rndm (nrofmon); for (mon = first_mon_info, i = 0; mon; mon = mon->next) if (i++ == monnr) @@ -1260,7 +1106,7 @@ return NULL; } - monnr = RANDOM () % i; + monnr = rndm (i); for (mon = first_mon_info; mon; mon = mon->next) if (mon->ob->level >= level && monnr-- == 0) return mon->ob; @@ -1277,16 +1123,15 @@ * Returns a description of the monster. This really needs to be * redone, as describe_item really gives a pretty internal description. */ - -char * +static const char * mon_desc (const object *mon) { - static char retbuf[HUGE_BUF]; + static dynbuf_text buf; buf.clear (); - sprintf (retbuf, " *** %s ***\n", &mon->name); - strcat (retbuf, describe_item (mon, NULL)); + buf.printf ("B<< %s >>\r", &mon->name); + buf << describe_item (mon, 0); - return retbuf; + return buf; } @@ -1294,8 +1139,7 @@ * found, it returns NULL (changed 0.94.3 to do this, since the * calling function (mon_info_msg) seems to expect that. */ - -object * +static object * get_next_mon (object *tmp) { objectlink *mon; @@ -1307,6 +1151,7 @@ /* didn't find a match */ if (!mon) return NULL; + if (mon->next) return mon->next->ob; else @@ -1314,21 +1159,16 @@ } - - /* mon_info_msg() - generate a message detailing the properties * of a randomly selected monster. */ - -char * -mon_info_msg (int level, int booksize) +static const char * +mon_info_msg (int level) { - static char retbuf[BOOK_BUF]; - char tmpbuf[HUGE_BUF]; - object *tmp; + static dynbuf_text buf; buf.clear (); /*preamble */ - strcpy (retbuf, "This beastiary contains:"); + buf << "This beastiary contains:\n"; /* lets print info on as many monsters as will fit in our * document. @@ -1337,27 +1177,17 @@ * of text! (and flood out the available number of titles * in the archive in a snap!) -b.t. */ - tmp = get_random_mon (level * 3); - while (tmp) + object *tmp = get_random_mon (level * 3); + while (tmp && buf.size () < BOOK_BUF) { /* monster description */ - sprintf (tmpbuf, "\n---\n%s", mon_desc (tmp)); - - if (!book_overflow (retbuf, tmpbuf, booksize)) - strcat (retbuf, tmpbuf); - else - break; + buf.printf ("\n%s\n", mon_desc (tmp)); /* Note that the value this returns is not based on level */ tmp = get_next_mon (tmp); } -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "\n mon_info_msg() created strng: %d\n", strlen (retbuf)); - fprintf (logfile, " MADE THIS:\n%s\n", retbuf); -#endif - - return retbuf; + return buf; } @@ -1368,18 +1198,19 @@ /* artifact_msg() - generate a message detailing the properties * of 1-6 artifacts drawn sequentially from the artifact list. */ - -char * -artifact_msg (int level, int booksize) +static const char * +artifact_msg (int level) { artifactlist *al = NULL; artifact *art; int chance, i, type, index; - int book_entries = level > 5 ? RANDOM () % 3 + RANDOM () % 3 + 2 : RANDOM () % level + 1; - char *ch, name[MAX_BUF], buf[BOOK_BUF], sbuf[MAX_BUF]; - static char retbuf[BOOK_BUF]; + int book_entries = level > 5 ? rndm (3) + rndm (3) + 2 : rndm (level) + 1; + const char *ch; + char name[MAX_BUF]; object *tmp = NULL; + static dynbuf_text buf; buf.clear (); + /* values greater than 5 create msg buffers that are too big! */ if (book_entries > 5) book_entries = 5; @@ -1392,7 +1223,7 @@ i = 0; do { - index = RANDOM () % (sizeof (art_name_array) / sizeof (arttypename)); + index = rndm (array_length (art_name_array)); type = art_name_array[index].type; al = find_artifactlist (type); i++; @@ -1400,38 +1231,40 @@ while ((al == NULL) && (i < 10)); if (i == 10) /* Unable to find a message */ - return ("None"); + return "None"; /* There is no reason to start on the artifact list at the begining. Lets * take our starting position randomly... */ art = al->items; - for (i = RANDOM () % level + RANDOM () % 2 + 1; i > 0; i--) + for (i = rndm (level) + rndm (2) + 1; i > 0; i--) { - if (art == NULL) + if (!art) art = al->items; /* hmm, out of stuff, loop back around */ + art = art->next; } /* the base 'generic' name for our artifact */ - strcpy (name, art_name_array[index].name); + assign (name, art_name_array[index].name); /* Ok, lets print out the contents */ - sprintf (retbuf, "Herein %s detailed %s...\n", book_entries > 1 ? "are" : "is", book_entries > 1 ? "some artifacts" : "an artifact"); + buf.printf ("Herein %s detailed %s...\n", + book_entries > 1 ? "are" : "is", + book_entries > 1 ? "some artifacts" : "an artifact"); /* artifact msg attributes loop. Lets keep adding entries to the 'book' * as long as we have space up to the allowed max # (book_entires) */ - while (book_entries > 0) + while (book_entries > 0 && buf.size () < BOOK_BUF) { - if (art == NULL) + if (!art) art = al->items; - /* separator of items */ - strcpy (buf, "--- \n"); + buf << '\n'; /* Name */ - if (art->allowed != NULL && strcmp (art->allowed->name, "All")) + if (art->allowed && art->allowed->name != shstr_All) { linked_char *temp, *next = art->allowed; @@ -1440,55 +1273,50 @@ temp = next; next = next->next; } - while (next && !RANDOM () % 2); - sprintf (buf, "%s A %s of %s", buf, &temp->name, &art->item->name); + while (next && rndm (2)); + + buf.printf ("A B<< %s of %s >>", &temp->name, &art->item->name); } else /* default name is used */ - sprintf (buf, "%s The %s of %s", buf, name, &art->item->name); + buf.printf ("The B<< %s of %s >>", name, &art->item->name); + + buf << " is "; /* chance of finding */ chance = (int) (100 * ((float) art->chance / al->total_chance)); if (chance >= 20) - sprintf (sbuf, "an uncommon"); + buf << "an uncommon"; else if (chance >= 10) - sprintf (sbuf, "an unusual"); + buf << "an unusual"; else if (chance >= 5) - sprintf (sbuf, "a rare"); + buf << "a rare"; else - sprintf (sbuf, "a very rare"); - sprintf (buf, "%s is %s\n", buf, sbuf); + buf << "a very rare"; /* value of artifact */ - sprintf (buf, "%s item with a value that is %d times normal.\n", buf, art->item->value); + buf << " item with a value that is " << art->item->value << " times normal.\n"; /* include the message about the artifact, if exists, and book * level is kinda high */ - if (art->item->msg && (RANDOM () % 4 + 1) < level && !((strlen (art->item->msg) + strlen (buf)) > BOOK_BUF)) - strcat (buf, art->item->msg); + if (art->item->msg + && rndm (4) + 1 < level) + buf << art->item->msg; /* properties of the artifact */ - tmp = get_object (); + tmp = object::create (); add_abilities (tmp, art->item); tmp->type = type; - SET_FLAG (tmp, FLAG_IDENTIFIED); - if ((ch = describe_item (tmp, NULL)) != NULL && strlen (ch) > 1) - sprintf (buf, "%s Properties of this artifact include: \n %s \n", buf, ch); - free_object (tmp); - /* add the buf if it will fit */ - if (!book_overflow (retbuf, buf, booksize)) - strcat (retbuf, buf); - else - break; + tmp->set_flag (FLAG_IDENTIFIED); + if ((ch = describe_item (tmp, 0)) && strlen (ch) > 1) + buf << "\rProperties of this artifact include:\r" << ch << "\n"; + + tmp->destroy (); art = art->next; book_entries--; } -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "artifact_msg() created strng: %d\n", strlen (retbuf)); - fprintf (logfile, " MADE THIS:\n%s", retbuf); -#endif - return retbuf; + return buf; } /***************************************************************************** @@ -1499,80 +1327,65 @@ * incantations/prayers (and some of their properties) belonging to * a given spellpath. */ - -char * -spellpath_msg (int level, int booksize) +static char * +spellpath_msg (int level) { - static char retbuf[BOOK_BUF]; - char tmpbuf[BOOK_BUF]; - int path = RANDOM () % NRSPELLPATHS, prayers = RANDOM () % 2; - int did_first_sp = 0; + static dynbuf_text buf; buf.clear (); + + int path = rndm (NRSPELLPATHS), prayers = rndm (2); uint32 pnum = (path == -1) ? PATH_NULL : spellpathdef[path]; archetype *at; /* Preamble */ - sprintf (retbuf, "Herein are detailed the names of %s\n", prayers ? "prayers" : "incantations"); + buf << "Herein are detailed the names of " + << (prayers ? "prayers" : "incantations"); if (path == -1) - strcat (retbuf, "having no known spell path.\n"); + buf << " having no known spell path.\n"; else - sprintf (retbuf, "%sbelonging to the path of %s:\n", retbuf, spellpathnames[path]); + buf << " belonging to the path of B<< " << spellpathnames[path] << " >>:\n\n"; - for (at = first_archetype; at != NULL; at = at->next) - { - /* Determine if this is an appropriate spell. Must - * be of matching path, must be of appropriate type (prayer - * or not), and must be within the valid level range. - */ - if (at->clone.type == SPELL && at->clone.path_attuned & pnum && - ((at->clone.stats.grace && prayers) || (at->clone.stats.sp && !prayers)) && (at->clone.level < (level * 8))) - { - strcpy (tmpbuf, at->clone.name); + int seen = 0; - if (book_overflow (retbuf, tmpbuf, booksize)) - break; - else - { - if (did_first_sp) - strcat (retbuf, ",\n"); - did_first_sp = 1; - strcat (retbuf, tmpbuf); - } - } - } - /* Geez, no spells were generated. */ - if (!did_first_sp) - { - if (RANDOM () % 4) /* usually, lets make a recursive call... */ - spellpath_msg (level, booksize); - else /* give up, cause knowing no spells exist for path is info too. */ - strcat (retbuf, "\n - no known spells exist -\n"); - } - else - { - strcat (retbuf, "\n"); - } - return retbuf; -} + for_all_archetypes (at) + /* Determine if this is an appropriate spell. Must + * be of matching path, must be of appropriate type (prayer + * or not), and must be within the valid level range. + */ + if (at->type == SPELL && at->path_attuned & pnum && + ((at->stats.grace && prayers) || (at->stats.sp && !prayers)) && (at->level < (level * 8))) + { + seen = 1; + buf << at->object::name << '\r'; + } + /* Geez, no spells were generated. */ + if (!seen) + if (rndm (4)) /* usually, lets make a recursive call... */ + return spellpath_msg (level); + else /* give up, cause knowing no spells exist for path is info too. */ + buf << "- no known spells exist.\n"; + return buf; +} /* formula_msg() - generate a message detailing the properties * of a randomly selected alchemical formula. */ - -void +static void make_formula_book (object *book, int level) { - char retbuf[BOOK_BUF], title[MAX_BUF]; + char title[MAX_BUF]; recipelist *fl; recipe *formula = NULL; int chance; + static dynbuf_text buf; buf.clear (); + /* the higher the book level, the more complex (ie number of * ingredients) the formula can be. */ - fl = get_formulalist (((RANDOM () % level) / 3) + 1); + fl = get_formulalist (rndm (level) / 3 + 1); if (!fl) fl = get_formulalist (1); /* safety */ @@ -1586,10 +1399,11 @@ } /* get a random formula, weighted by its bookchance */ - chance = RANDOM () % fl->total_chance; - for (formula = fl->items; formula != NULL; formula = formula->next) + chance = rndm (fl->total_chance); + for (formula = fl->items; formula; formula = formula->next) { chance -= formula->chance; + if (chance <= 0) break; } @@ -1599,323 +1413,275 @@ book->msg = "\n"; new_text_name (book, 4); add_author (book, 4); - + return; } - else - { - /* looks like a formula was found. Base the amount - * of information on the booklevel and the spellevel - * of the formula. */ - - const char *op_name = formula->arch_name[RANDOM () % formula->arch_names]; - archetype *at; - /* preamble */ - sprintf (retbuf, "Herein is described a project using %s: \n", formula->skill ? &formula->skill : "an unknown skill"); + /* looks like a formula was found. Base the amount + * of information on the booklevel and the spellevel + * of the formula. */ - if ((at = archetype::find (op_name)) != (archetype *) NULL) - op_name = at->clone.name; - else - LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name); - - /* item name */ - if (strcmp (formula->title, "NONE")) - { - sprintf (retbuf, "%sThe %s of %s", retbuf, op_name, &formula->title); - /* This results in things like pile of philo. sulfur. - * while philo. sulfur may look better, without this, - * you get things like 'the wise' because its missing the - * water of section. - */ - sprintf (title, "%s: %s of %s", - formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title); - } - else - { - sprintf (retbuf, "%sThe %s", retbuf, op_name); - sprintf (title, "%s: %s", formula_book_name[RANDOM () % (sizeof (formula_book_name) / sizeof (char *))], op_name); - if (at->clone.title) - { - strcat (retbuf, " "); - strcat (retbuf, at->clone.title); - strcat (title, " "); - strcat (title, at->clone.title); - } - } - /* Lets name the book something meaningful ! */ - book->name = title; - book->title = NULL; + const char *op_name = formula->arch_name [rndm (formula->arch_names)]; + archetype *at; - /* ingredients to make it */ - if (formula->ingred != NULL) - { - linked_char *next; - archetype *at; + /* preamble */ + buf << "Herein is described a project using B<< " + << (formula->skill ? &formula->skill : "an unknown skill") + << " >>:\n\n"; - at = archetype::find (formula->cauldron); + if ((at = archetype::find (op_name))) + op_name = at->object::name; + else + LOG (llevError, "formula_msg() can't find arch %s for formula.\n", op_name); - sprintf (retbuf + strlen (retbuf), - " may be made at %s using the following ingredients:\n", at ? query_name (&at->clone) : "an unknown place"); + /* item name */ + if (formula->title != shstr_NONE) + { + buf.printf ("The B<< %s of %s >>", op_name, &formula->title); + /* This results in things like pile of philo. sulfur. + * while philo. sulfur may look better, without this, + * you get things like 'the wise' because its missing the + * water of section. + */ + sprintf (title, "%s: %s of %s", + formula_book_name [rndm (sizeof (formula_book_name) / sizeof (char *))], op_name, &formula->title); + } + else + { + buf << "The B<< " << op_name; - for (next = formula->ingred; next != NULL; next = next->next) - { - strcat (retbuf, next->name); - strcat (retbuf, "\n"); - } + sprintf (title, "%s: %s", formula_book_name [rndm (sizeof (formula_book_name) / sizeof (char *))], op_name); + if (at->title) + { + buf << " " << at->title; + strcat (title, " "); + strcat (title, at->title); } - else - LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title); - if (retbuf[strlen (retbuf) - 1] != '\n') - strcat (retbuf, "\n"); - book->msg = retbuf; + buf << " >>"; } -} + /* Lets name the book something meaningful ! */ + book->name = title; + book->title = NULL; -/* msgfile_msg() - generate a message drawn randomly from a - * file in lib/. Level currently has no effect on the message - * which is returned. - */ + /* ingredients to make it */ + if (formula->ingred) + { + linked_char *next; + archetype *at; -char * -msgfile_msg (int level, int booksize) -{ - static char retbuf[BOOK_BUF]; - int i, msgnum; - linked_char *msg = NULL; + at = archetype::find (formula->cauldron); - /* get a random message for the 'book' from linked list */ - if (nrofmsg > 1) - { - msg = first_msg; - msgnum = RANDOM () % nrofmsg; - for (i = 0; msg && i < nrofmsg && i != msgnum; i++) - msg = msg->next; - } + buf.printf (" may be made at %s using the following ingredients:\n\n", + at ? query_name (at) : "an appropriate place"); - if (msg && !book_overflow (retbuf, msg->name, booksize)) - strcpy (retbuf, msg->name); + for (next = formula->ingred; next; next = next->next) + buf << next->name << '\r'; + } else - sprintf (retbuf, "\n "); + LOG (llevError, "formula_msg() no ingredient list for object %s of %s\n", op_name, &formula->title); -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "\n info_list_msg() created strng: %d\n", strlen (retbuf)); - LOG (llevDebug, " MADE THIS:\n%s\n", retbuf); -#endif - - return retbuf; + book->msg = buf; } +#define DESCRIBE_PATH(retbuf, variable, name) \ + if(variable) { \ + int i,j=0; \ + strcat(retbuf,"(" name ": "); \ + for(i=0; iname; /* preamble.. */ - sprintf (retbuf, "This document contains knowledge concerning\n"); - sprintf (retbuf, "%sthe diety %s", retbuf, name); + buf << "This document contains knowledge concerning the diety B<< " + << name << " >>"; /* Always have as default information the god's descriptive terms. */ if (nstrtok (god->msg, ",") > 0) - { - strcat (retbuf, ", known as"); - strcat (retbuf, strtoktolin (god->msg, ",")); - } + buf << ", known as" << strtoktolin (god->msg, ","); else - strcat (retbuf, "..."); + buf << "..."; - strcat (retbuf, "\n ---\n"); - introlen = strlen (retbuf); /* so we will know if no new info is added later */ + buf << "\n\n"; + + int introlen = buf.size (); /* so we will know if no new info is added later */ /* Information about the god is random, and based on the level of the * 'book'. Probably there is a more intellegent way to implement * this ... */ - - while (level > 0) + while (level > 0 && buf.size () < BOOK_BUF) { - sprintf (buf, " "); - if (level == 2 && RANDOM () % 2) + if (level == 2 && rndm (2)) { /* enemy god */ const char *enemy = god->title; if (enemy) - sprintf (buf, "The gods %s and %s are enemies.\n ---\n", name, enemy); + buf.printf ("The gods %s and %s are enemies.\r", name, enemy); } - if (level == 3 && RANDOM () % 2) + + if (level == 3 && rndm (2)) { /* enemy race, what the god's holy word effects */ const char *enemy = god->slaying; + int i; if (enemy && !(god->path_denied & PATH_TURNING)) if ((i = nstrtok (enemy, ",")) > 0) { - char tmpbuf[MAX_BUF]; + buf << "The holy words of " << name + << " have the power to slay creatures belonging to the "; - sprintf (buf, "The holy words of %s have the power to\n", name); - strcat (buf, "slay creatures belonging to the "); if (i > 1) - sprintf (tmpbuf, "following \n races:%s", strtoktolin (enemy, ",")); + buf << "following races:" << strtoktolin (enemy, ","); else - sprintf (tmpbuf, "race of%s", strtoktolin (enemy, ",")); - sprintf (buf, "%s%s\n ---\n", buf, tmpbuf); + buf << "race of" << strtoktolin (enemy, ","); + + buf << '\r'; } } - if (level == 4 && RANDOM () % 2) - { /* Priest of god gets these protect,vulnerable... */ - char tmpbuf[MAX_BUF], *cp; - cp = describe_resistance (god, 1); - - if (*cp) + if (level == 4 && rndm (2)) + { /* Priest of god gets these protect,vulnerable... */ + if (const char *cp = describe_resistance (god, 1)) { /* This god does have protections */ - sprintf (tmpbuf, "%s has a potent aura which is extended\n", name); - strcat (tmpbuf, "faithful priests. The effects of this aura include:\n"); - strcat (tmpbuf, cp); - strcat (buf, tmpbuf); - strcat (buf, "\n ---\n"); + buf << name + << " has a potent aura which is extended to" + " faithful priests. The effects of this aura include: " + << cp + << ".\r"; } - else - sprintf (buf, " "); } - if (level == 5 && RANDOM () % 2) + + if (level == 5 && rndm (2)) { /* aligned race, summoning */ const char *race = god->race; /* aligned race */ + int i; if (race && !(god->path_denied & PATH_SUMMON)) if ((i = nstrtok (race, ",")) > 0) { - char tmpbuf[MAX_BUF]; - - sprintf (buf, "Creatures sacred to %s include the \n", name); + buf << "Creatures sacred to " << name << " include the "; if (i > 1) - sprintf (tmpbuf, "following \n races:%s", strtoktolin (race, ",")); + buf << "following races:" << strtoktolin (race, ","); else - sprintf (tmpbuf, "race of%s", strtoktolin (race, ",")); - sprintf (buf, "%s%s\n ---\n", buf, tmpbuf); + buf << "race of" << strtoktolin (race, ","); + + buf << '\r'; } } - if (level == 6 && RANDOM () % 2) - { /* blessing,curse properties of the god */ - char tmpbuf[MAX_BUF], *cp; - - cp = describe_resistance (god, 1); - if (*cp) + if (level == 6 && rndm (2)) + { /* blessing,curse properties of the god */ + if (const char *cp = describe_resistance (god, 1)) { /* This god does have protections */ - sprintf (tmpbuf, "\nThe priests of %s are known to be able to \n", name); - strcat (tmpbuf, "bestow a blessing which makes the recipient\n"); - strcat (tmpbuf, cp); - strcat (buf, tmpbuf); - strcat (buf, "\n ---\n"); + buf << "The priests of " << name + << " are known to be able to " + "bestow a blessing which makes the recipient " + << cp + << '\r'; } - else - sprintf (buf, " "); - } - if (level == 8 && RANDOM () % 2) - { /* immunity, holy possession */ - int has_effect = 0, tmpvar; - char tmpbuf[MAX_BUF]; - sprintf (tmpbuf, "\n"); - sprintf (tmpbuf, "The priests of %s are known to make cast a mighty \n", name); + if (level == 8 && rndm (2)) + { /* immunity, holy possession */ + buf << "The priests of " << name + << " are known to make cast a mighty" + " prayer of possession"; + + int first = 1; - strcat (tmpbuf, "prayer of possession which gives the recipient\n"); + for (int i = 0; i < NROFATTACKS; i++) + if (god->resist[i] == 100) + { + if (first) + { + buf << " which gives the recipient"; + first = 0; + } + else + buf << ", "; - for (tmpvar = 0; tmpvar < NROFATTACKS; tmpvar++) - { - if (god->resist[tmpvar] == 100) - { - has_effect = 1; - sprintf (tmpbuf + strlen (tmpbuf), "Immunity to %s", attacktype_desc[tmpvar]); - } - } - if (has_effect) - { - strcat (buf, tmpbuf); - strcat (buf, "\n ---\n"); + buf << " immunity to " << attacktype_desc[i]; } - else - sprintf (buf, " "); + + buf << ".\r"; } - if (level == 12 && RANDOM () % 2) + + if (level == 12 && rndm (2)) { /* spell paths */ + //TODO: int has_effect = 0, tmpvar; char tmpbuf[MAX_BUF]; - sprintf (tmpbuf, "\n"); sprintf (tmpbuf, "It is rarely known fact that the priests of %s\n", name); strcat (tmpbuf, "are mystically transformed. Effects of this include:\n"); + if ((tmpvar = god->path_attuned)) { has_effect = 1; DESCRIBE_PATH (tmpbuf, tmpvar, "Attuned"); } + if ((tmpvar = god->path_repelled)) { has_effect = 1; DESCRIBE_PATH (tmpbuf, tmpvar, "Repelled"); } + if ((tmpvar = god->path_denied)) { has_effect = 1; DESCRIBE_PATH (tmpbuf, tmpvar, "Denied"); } + if (has_effect) - { - strcat (buf, tmpbuf); - strcat (buf, "\n ---\n"); - } + buf << tmpbuf << '\r'; else - sprintf (buf, " "); + buf << '\r'; } - /* check to be sure new buffer size dont exceed either - * the maximum buffer size, or the 'natural' size of the - * book... - */ - if (book_overflow (retbuf, buf, booksize)) - break; - else if (strlen (buf) > 1) - strcat (retbuf, buf); level--; } - if (strlen (retbuf) == introlen) - { /* we got no information beyond the preamble! */ - strcat (retbuf, " [Unfortunately the rest of the information is\n"); - strcat (retbuf, " hopelessly garbled!]\n ---\n"); - } -#ifdef BOOK_MSG_DEBUG - LOG (llevDebug, "\n god_info_msg() created strng: %d\n", strlen (retbuf)); - fprintf (logfile, " MADE THIS:\n%s", retbuf); -#endif - return retbuf; + + if (buf.size () == introlen) + /* we got no information beyond the preamble! */ + buf << "[Unfortunately the rest of the information is hopelessly garbled!]"; + + return buf; } -/* tailor_readable_ob()- The main routine. This chooses a random - * message to put in given readable object (type==BOOK) which will - * be referred hereafter as a 'book'. We use the book level to de- - * termine the value of the information we will insert. Higher - * values mean the book will (generally) have better/more info. +/* tailor_readable_ob()- The main routine. This chooses a random + * message to put in given readable object (type==BOOK) which will + * be referred hereafter as a 'book'. We use the book level to de- + * termine the value of the information we will insert. Higher + * values mean the book will (generally) have better/more info. * See individual cases as to how this will be utilized. - * "Book" name/content length are based on the weight of the + * "Book" name/content length are based on the weight of the * document. If the value of msg_type is negative, we will randomly - * choose the kind of message to generate. + * choose the kind of message to generate. * -b.t. thomas@astro.psu.edu * * book is the object we are creating into. @@ -1923,13 +1689,10 @@ * message type - otherwise a random value is used. * */ - void tailor_readable_ob (object *book, int msg_type) { - char msgbuf[BOOK_BUF]; - int level = book->level ? (RANDOM () % book->level) + 1 : 1; - int book_buf_size; + int level = book->level ? rndm (book->level) + 1 : 1; /* safety */ if (book->type != BOOK) @@ -1938,9 +1701,6 @@ if (level <= 0) return; /* if no level no point in doing any more... */ - /* Max text length this book can have. */ - book_buf_size = BOOKSIZE (book); - /* &&& The message switch &&& */ /* Below all of the possible types of messages in the "book"s. */ @@ -1952,95 +1712,49 @@ * and add_authour(). * 4) you may want separate authour/book name arrays in read.h */ - - msg_type = msg_type > 0 ? msg_type : (RANDOM () % 6); + const char *new_msg = ""; + msg_type = msg_type > 0 ? msg_type : rndm (8); switch (msg_type) { - case 1: /* monster attrib */ - strcpy (msgbuf, mon_info_msg (level, book_buf_size)); - break; - case 2: /* artifact attrib */ - strcpy (msgbuf, artifact_msg (level, book_buf_size)); - break; - case 3: /* grouping incantations/prayers by path */ - strcpy (msgbuf, spellpath_msg (level, book_buf_size)); - break; - case 4: /* describe an alchemy formula */ - make_formula_book (book, level); - /* make_formula_book already gives title */ - return; - break; - case 5: /* bits of information about a god */ - strcpy (msgbuf, god_info_msg (level, book_buf_size)); - break; - case 0: /* use info list in lib/ */ - default: - strcpy (msgbuf, msgfile_msg (level, book_buf_size)); - break; + case 1: /* monster attrib */ + new_msg = mon_info_msg (level); + break; + case 2: /* artifact attrib */ + new_msg = artifact_msg (level); + break; + case 3: /* grouping incantations/prayers by path */ + new_msg = spellpath_msg (level); + break; + case 4: /* describe an alchemy formula */ + make_formula_book (book, level); + /* make_formula_book already gives title */ + return; + case 5: /* bits of information about a god */ + new_msg = god_info_msg (level); + break; + case 0: /* use info list in lib/ */ + default: + cfperl_make_book (book, level); + /* already gives title */ + return; } - strcat (msgbuf, "\n"); /* safety -- we get ugly map saves/crashes w/o this */ - if (strlen (msgbuf) > 1) + if (strlen (new_msg) > 1) { - book->msg = msgbuf; + book->msg = new_msg; /* lets give the "book" a new name, which may be a compound word */ change_book (book, msg_type); } - } - -/***************************************************************************** - * - * Cleanup routine for readble stuff. - * - *****************************************************************************/ - -void -free_all_readable (void) -{ - titlelist *tlist, *tnext; - title *title1, *titlenext; - linked_char *lmsg, *nextmsg; - objectlink *monlink, *nextmon; - - LOG (llevDebug, "freeing all book information\n"); - - for (tlist = booklist; tlist != NULL; tlist = tnext) - { - tnext = tlist->next; - - for (title1 = tlist->first_book; title1; title1 = titlenext) - { - titlenext = title1->next; - delete title1; - } - - delete tlist; - } - for (lmsg = first_msg; lmsg; lmsg = nextmsg) - { - nextmsg = lmsg->next; - delete lmsg; - } - for (monlink = first_mon_info; monlink; monlink = nextmon) - { - nextmon = monlink->next; - free (monlink); - } -} - - /***************************************************************************** * * Writeback routine for updating the bookarchive. * ****************************************************************************/ - /* write_book_archive() - write out the updated book archive */ - void -write_book_archive (void) +write_book_archive () { FILE *fp; int index = 0; @@ -2051,15 +1765,14 @@ /* If nothing changed, don't write anything */ if (!need_to_write_bookarchive) return; + need_to_write_bookarchive = 0; sprintf (fname, "%s/bookarch", settings.localdir); LOG (llevDebug, "Updating book archive: %s...\n", fname); if ((fp = fopen (fname, "w")) == NULL) - { - LOG (llevDebug, "Can't open book archive file %s\n", fname); - } + LOG (llevDebug, "Can't open book archive file %s\n", fname); else { while (bl) @@ -2076,19 +1789,23 @@ fprintf (fp, "index %d\n", book->msg_index); fprintf (fp, "end\n"); } + bl = bl->next; index++; } + fclose (fp); chmod (fname, SAVE_MODE); } } + readable_message_type * get_readable_message_type (object *readable) { uint8 subtype = readable->subtype; if (subtype > last_readable_subtype) - return &(readable_message_types[0]); - return &(readable_message_types[subtype]); + return &readable_message_types[0]; + + return &readable_message_types[subtype]; }