82 #define MAX_TITLE_CHECK 20
85 #define MSGTYPE_MONSTER 1
86 #define MSGTYPE_ARTIFACT 2
87 #define MSGTYPE_SPELLPATH 3
88 #define MSGTYPE_ALCHEMY 4
89 #define MSGTYPE_GODS 5
90 #define MSGTYPE_MSGFILE 6
97 #define arraysize(arrayname) (sizeof(arrayname)/sizeof(*(arrayname)))
126 static void add_book(
title *book,
int type,
const char *fname,
int lineno);
225 {
"Missile Weapon",
BOW },
226 {
"Missile",
ARROW },
227 {
"Hand Weapon",
WEAPON },
228 {
"Artifact",
SKILL },
348 "magical manufacture",
350 "philosophical items",
610 LOG(
llevInfo,
"Warning: invalid book index %d, using 0 instead\n", i);
614 for (tl = booklist, number = i; tl && number; tl = tl->
next, number--) {
636 static int nstrtok(
const char *buf1,
const char *buf2) {
643 snprintf(buf,
sizeof(buf),
"%s", buf1);
644 for (tbuf = strtok(buf, buf2); tbuf; tbuf = strtok(NULL, buf2)) {
666 static char *
strtoktolin(
const char *buf1,
const char *buf2,
char *retbuf,
size_t size) {
667 int maxi, i =
nstrtok(buf1, buf2);
671 snprintf(buf,
sizeof(buf),
"%s", buf1);
673 for (tbuf = strtok(buf, buf2); tbuf && i > 0; tbuf = strtok(NULL, buf2)) {
674 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
"%s", tbuf);
676 if (i == 1 && maxi > 1)
677 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
" and ");
678 else if (i > 0 && maxi > 1)
679 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
", ");
681 snprintf(retbuf+strlen(retbuf), size-strlen(retbuf),
".");
718 static int did_init_msgfile = 0;
720 if (did_init_msgfile)
722 did_init_msgfile = 1;
734 for (lineno = 1; fgets(buf,
MAX_BUF, fp) != NULL; lineno++) {
737 cp = strchr(buf,
'\n');
739 while (cp > buf && (cp[-1] ==
' ' || cp[-1] ==
'\t'))
744 if (strcmp(buf,
"ENDMSG") == 0) {
746 LOG(
llevDebug,
"Warning: this string exceeded max book buf size:\n");
756 strcat(msgbuf,
"\n");
757 }
else if (error_lineno != 0) {
758 LOG(
llevInfo,
"Warning: truncating book at %s, line %d\n", fname, error_lineno);
761 }
else if (strcmp(buf,
"MSG") == 0) {
762 error_lineno = lineno;
766 LOG(
llevInfo,
"Warning: syntax error at %s, line %d\n", fname, lineno);
772 #ifdef BOOK_MSG_DEBUG
786 int comp, nroftitle = 0;
788 static int did_init_barch = 0;
798 LOG(
llevDebug,
" Reading bookarch from %s...\n", fname);
812 for (lineno = 1; fgets(buf,
MAX_BUF, fp) != NULL; lineno++) {
818 cp = strchr(buf,
'\n');
820 while (cp > buf && (cp[-1] ==
' ' || cp[-1] ==
'\t'))
825 if (strncmp(buf,
"title ", 6) == 0) {
828 while (*cp ==
' ' || *cp ==
'\t')
831 LOG(
llevInfo,
"Warning: missing book title at %s, line %d\n", fname, lineno);
839 }
else if (book == NULL) {
842 LOG(
llevInfo,
"Warning: expecting 'title' at %s, line %d\n", fname, lineno);
844 }
else if (strncmp(buf,
"authour ", 8) == 0) {
846 while (*cp ==
' ' || *cp ==
'\t')
849 LOG(
llevInfo,
"Warning: missing book authour at %s, line %d\n", fname, lineno);
853 }
else if (strncmp(buf,
"arch ", 5) == 0) {
855 while (*cp ==
' ' || *cp ==
'\t')
858 LOG(
llevInfo,
"Warning: missing book arch at %s, line %d\n", fname, lineno);
862 }
else if (sscanf(buf,
"level %d%n", &value, &len) == 1 && len == (
int)strlen(buf)) {
864 }
else if (sscanf(buf,
"type %d%n", &value, &len) == 1 && len == (
int)strlen(buf)) {
866 }
else if (sscanf(buf,
"size %d%n", &value, &len) == 1 && len == (
int)strlen(buf)) {
868 }
else if (sscanf(buf,
"index %d%n", &value, &len) == 1 && len == (
int)strlen(buf)) {
870 }
else if (strcmp(buf,
"end") == 0) {
871 add_book(book, type, fname, lineno);
875 LOG(
llevInfo,
"Warning: syntax error at %s, line %d\n", fname, lineno);
879 LOG(
llevInfo,
"Warning: missing 'end' at %s, line %d\n", fname, lineno);
880 add_book(book, type, fname, lineno);
889 #ifdef BOOK_MSG_DEBUG
890 LOG(
llevDebug,
"\n init_book_archive() got %d titles.\n", nroftitle);
902 static void add_book(
title *book,
int type,
const char *fname,
int lineno) {
906 LOG(
llevInfo,
"Warning: book with no type at %s, line %d; using type 0\n", fname, lineno);
922 static int did_init_mon_info = 0;
924 if (did_init_mon_info)
926 did_init_mon_info = 1;
939 first_mon_info =
mon;
953 static int did_this = 0;
991 return (
title *)NULL;
995 return (
title *)NULL;
997 length = strlen(book->
msg);
1001 #ifdef ARCHIVE_DEBUG
1007 return (
title *)NULL;
1052 if (book->
weight > 2000) {
1076 if (msgtype < 0 || strlen(op->
msg) < 5)
1105 snprintf(title,
sizeof(title),
"of %s", name);
1149 LOG(
llevError,
"add_book_to_list can't get booklist!\n");
1168 #ifdef ARCHIVE_DEBUG
1192 LOG(
llevError,
"change_book_name() called w/ illegal obj type.\n");
1206 if (strlen(book->
msg) > 5 && (t =
find_title(book, msgtype))) {
1223 const char *old_title;
1224 const char *old_name;
1234 LOG(
llevError,
"change_book_name(): can't find title list\n");
1239 if (numb == maxnames) {
1240 #ifdef ARCHIVE_DEBUG
1241 LOG(
llevDebug,
"titles for list %d full (%d possible).\n", msgtype, maxnames);
1243 if (old_title != NULL)
1267 #ifdef ARCHIVE_DEBUG
1268 LOG(
llevDebug,
"Failed to obtain unique title for %s %s (names:%d/%d)\n", book->
name, book->
title, numb, maxnames);
1284 }
else if (book->
title && strlen(book->
msg) > 5) {
1288 if (old_title != NULL)
1321 if (!
nrofmon || !first_mon_info)
1322 return (
object *)NULL;
1328 for (mon = first_mon_info, i = 0;
mon; mon = mon->
next, i++)
1333 LOG(
llevError,
"get_random_mon: Didn't find a monster when we should have\n");
1352 for (mon = first_mon_info, i = 0;
mon; mon = mon->
next)
1357 LOG(
llevError,
"get_random_mon() couldn't return monster for level %d\n", level);
1362 for (mon = first_mon_info;
mon; mon = mon->
next)
1363 if (mon->
ob->
level >= level && monnr-- == 0)
1366 LOG(
llevError,
"get_random_mon(): didn't find a monster when we should have\n");
1385 describe_item(mon, NULL, buf+strlen(buf), size-strlen(buf));
1403 for (mon = first_mon_info;
mon; mon = mon->
next)
1413 return first_mon_info->
ob;
1434 snprintf(buf, booksize,
"This beastiary contains:");
1445 snprintf(tmpbuf,
sizeof(tmpbuf),
"\n---\n%s",
mon_desc(tmp, desc,
sizeof(desc)));
1449 snprintf(buf+strlen(buf), booksize-strlen(buf),
"%s", tmpbuf);
1452 #ifdef BOOK_MSG_DEBUG
1453 LOG(
llevDebug,
"\n mon_info_msg() created strng: %d\n", strlen(retbuf));
1454 fprintf(
logfile,
" MADE THIS:\n%s\n", retbuf);
1480 int chance, i, type, index;
1481 int book_entries = level > 5 ? RANDOM()%3+RANDOM()%3+2 : RANDOM()%level+1;
1486 if (book_entries > 5)
1496 index = RANDOM()%
arraysize(art_name_array);
1497 type = art_name_array[index].
type;
1500 }
while (al == NULL && i < 10);
1503 snprintf(retbuf, booksize,
"None");
1510 for (i = RANDOM()%level+RANDOM()%2+1; i > 0; i--) {
1517 snprintf(retbuf, booksize,
"Herein %s detailed %s...\n", book_entries > 1 ?
"are" :
"is", book_entries > 1 ?
"some artifacts" :
"an artifact");
1522 while (book_entries > 0) {
1527 snprintf(buf,
sizeof(buf),
"---\n");
1536 }
while (next != (
linked_char *)NULL && RANDOM()%2);
1537 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
" A %s of %s", temp->
name, art->
item->
name);
1540 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
" The %s of %s", art_name_array[index].name, art->
item->
name);
1546 snprintf(sbuf,
sizeof(sbuf),
"an uncommon");
1547 else if (chance >= 10)
1548 snprintf(sbuf,
sizeof(sbuf),
"an unusual");
1549 else if (chance >= 5)
1550 snprintf(sbuf,
sizeof(sbuf),
"a rare");
1552 snprintf(sbuf,
sizeof(sbuf),
"a very rare");
1553 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
" is %s\n", sbuf);
1556 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
" item with a value that is %d times normal.\n",
1561 if (art->
item->
msg && RANDOM()%4+1 < level
1563 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
"%s", art->
item->
msg);
1571 if (strlen(sbuf) > 1)
1572 snprintf(buf+strlen(buf),
sizeof(buf)-strlen(buf),
" Properties of this artifact include:\n %s\n", sbuf);
1577 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf),
"%s", buf);
1583 #ifdef BOOK_MSG_DEBUG
1584 LOG(
llevDebug,
"artifact_msg() created strng: %d\n", strlen(retbuf));
1585 fprintf(
logfile,
" MADE THIS:\n%s", retbuf);
1608 int path = RANDOM()%
NRSPELLPATHS, prayers = RANDOM()%2;
1609 int did_first_sp = 0;
1614 snprintf(retbuf, booksize,
"Herein are detailed the names of %s\n", prayers ?
"prayers" :
"incantations");
1616 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf),
"belonging to the path of %s:\n",
spellpathnames[path]);
1631 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf),
",\n");
1637 if (!did_first_sp) {
1641 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf),
"\n - no known spells exist -\n");
1643 snprintf(retbuf+strlen(retbuf), booksize-strlen(retbuf),
"\n");
1661 const char *op_name;
1680 for (formula = fl->
items; formula != NULL; formula = formula->
next) {
1681 chance -= formula->
chance;
1698 snprintf(retbuf,
sizeof(retbuf),
"Herein is described a project using %s:\n", formula->
skill ? formula->
skill :
"an unknown skill");
1703 LOG(
llevError,
"formula_msg() can't find arch %s for formula.\n", op_name);
1712 if (strcmp(formula->
title,
"NONE")) {
1713 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
"The %s of %s", op_name, formula->
title);
1721 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
"The %s", op_name);
1724 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
" %s", at->
clone.
title);
1738 if (formula->
ingred != NULL) {
1747 snprintf(name,
sizeof(name),
"an unknown place");
1749 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
1750 " may be made at %s using the following ingredients:\n", name);
1752 for (next = formula->
ingred; next != NULL; next = next->
next) {
1753 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
"%s\n", next->
name);
1756 LOG(
llevError,
"formula_msg() no ingredient list for object %s of %s\n", op_name, formula->
title);
1757 if (retbuf[strlen(retbuf)-1] !=
'\n')
1758 snprintf(retbuf+strlen(retbuf),
sizeof(retbuf)-strlen(retbuf),
"\n");
1783 for (i = 0; msg && i <
nrofmsg && i != msgnum; i++)
1790 snprintf(retbuf,
sizeof(retbuf),
"\n <undecipherable text>");
1792 #ifdef BOOK_MSG_DEBUG
1793 LOG(
llevDebug,
"\n info_list_msg() created strng: %d\n", strlen(retbuf));
1817 size_t retlen, buflen;
1823 LOG(
llevError,
"common/readable.c:god_info_msg() - passed in booksize (%lu) is larger than book buffer (%d)\n", (
unsigned long)booksize,
BOOK_BUF);
1828 return (
char *)NULL;
1832 snprintf(retbuf,
BOOK_BUF,
"This document contains knowledge concerning the diety %s", name);
1834 retlen = strlen(retbuf);
1856 if (level == 2 && RANDOM()%2) {
1862 if (level == 3 && RANDOM()%2) {
1864 const char *enemy = god->
slaying;
1867 && (i =
nstrtok(enemy,
",")) > 0) {
1870 snprintf(buf,
BOOK_BUF,
"The holy words of %s have the power to slay creatures belonging to the ", name);
1876 buflen = strlen(buf);
1880 if (level == 4 && RANDOM()%2) {
1887 snprintf(buf,
BOOK_BUF,
"%s has a potent aura which is extended to faithful priests. The effects of this aura include:\n%s\n ---\n", name, cp);
1890 if (level == 5 && RANDOM()%2) {
1892 const char *race = god->
race;
1906 buflen = strlen(buf);
1911 if (level == 6 && RANDOM()%2) {
1918 snprintf(buf,
MAX_BUF,
"\nThe priests of %s are known to be able to bestow a blessing which makes the recipient %s\n ---\n", name, cp);
1921 if (level == 8 && RANDOM()%2) {
1923 int has_effect = 0, tmpvar;
1926 snprintf(buf,
MAX_BUF,
"\nThe priests of %s are known to make cast a mighty prayer of possession which gives the recipient", name);
1928 for (tmpvar = 0; tmpvar <
NROFATTACKS; tmpvar++) {
1929 if (god->
resist[tmpvar] == 100) {
1935 buflen = strlen(buf);
1943 if (level == 12 && RANDOM()%2) {
1947 snprintf(buf,
MAX_BUF,
"It is rarely known fact that the priests of %s are mystically transformed. Effects of this include:\n", name);
1948 buflen = strlen(buf);
1976 if (strlen(buf) > 1)
1981 if (retlen == introlen) {
1983 safe_strcat(retbuf,
" Unfortunately the rest of the information is hopelessly garbled!\n ---\n", &retlen,
BOOK_BUF);
1985 #ifdef BOOK_MSG_DEBUG
1986 LOG(
llevDebug,
"\n god_info_msg() created strng: %d\n", strlen(retbuf));
1987 fprintf(
logfile,
" MADE THIS:\n%s", retbuf);
2012 int level = book->
level ? RANDOM()%book->
level+1 : 1;
2013 size_t book_buf_size;
2024 book_buf_size -= strlen(
"\n");
2038 msg_type = msg_type > 0 ? msg_type : RANDOM()%6;
2064 strcpy(msgbuf,
msgfile_msg(level, book_buf_size));
2068 strcat(msgbuf,
"\n");
2069 if (strlen(msgbuf) > strlen(
"\n")) {
2086 title *title1, *titlenext;
2092 for (tlist = booklist; tlist != NULL; tlist = tnext) {
2093 tnext = tlist->
next;
2094 for (title1 = tlist->
first_book; title1; title1 = titlenext) {
2095 titlenext = title1->
next;
2106 for (lmsg = first_msg; lmsg; lmsg = nextmsg) {
2107 nextmsg = lmsg->
next;
2112 for (monlink = first_mon_info; monlink; monlink = nextmon) {
2113 nextmon = monlink->
next;
2139 LOG(
llevDebug,
"Updating book archive: %s...\n", fname);
2141 fp = fopen(fname,
"w");
2143 LOG(
llevDebug,
"Can't open book archive file %s\n", fname);
2150 fprintf(fp,
"title %s\n", book->
name);
2151 fprintf(fp,
"authour %s\n", book->
authour);
2152 fprintf(fp,
"arch %s\n", book->
archname);
2153 fprintf(fp,
"level %d\n", book->
level);
2154 fprintf(fp,
"type %d\n", index);
2156 fprintf(fp,
"size %lu\n", (
unsigned long)book->
size);
2157 fprintf(fp,
"index %d\n", book->
msg_index);
2158 fprintf(fp,
"end\n");
2166 if (fclose(fp) != 0) {
2185 return &readable_message_types[0];
2186 return &readable_message_types[subtype];
static const char *const heavy_book_name[]
archetype * find_archetype(const char *name)
static char * msgfile_msg(int level, size_t booksize)
static char * strtoktolin(const char *buf1, const char *buf2, char *retbuf, size_t size)
#define MSG_TYPE_PAPER_LETTER_OLD_1
#define MSG_TYPE_CARD_STRANGE_2
static void init_msgfile(void)
#define MSG_TYPE_MONUMENT_STONE_2
#define MSG_TYPE_SIGN_DIR_LEFT
#define MSG_TYPE_MONUMENT_GRAVESTONE_2
static void make_formula_book(object *book, int level)
static titlelist * get_titlelist(int i)
static void add_book_to_list(const object *book, int msgtype)
#define MSG_TYPE_BOOK_CLASP_1
#define MSG_TYPE_MONUMENT_STATUE_1
object * get_random_mon(int level)
#define MSG_TYPE_BOOK_QUARTO_2
struct artifactstruct * items
static const arttypename art_name_array[]
void free_string(sstring str)
static char * artifact_msg(int level, char *retbuf, size_t booksize)
static const int last_readable_subtype
static const char *const path_book_name[]
#define MSG_TYPE_PAPER_LETTER_OLD_2
static void init_book_archive(void)
#define MSG_TYPE_CARD_STRANGE_1
#define MSG_TYPE_BOOK_SPELL_EVOKER
#define MSG_TYPE_CARD_MONEY_3
#define MSG_TYPE_MONUMENT_GRAVESTONE_3
#define MSG_TYPE_CARD_ELEGANT_2
void close_and_delete(FILE *fp, int compressed)
static void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
static title * find_title(const object *book, int msgtype)
static object * get_next_mon(const object *tmp)
const char *const spellpathnames[NRSPELLPATHS]
#define MSG_TYPE_SIGN_DIR_RIGHT
#define MSG_TYPE_BOOK_SPELL_PRAYER
void add_abilities(object *op, object *change)
#define MSG_TYPE_MONUMENT_STATUE_2
static char * spellpath_msg(int level, char *retbuf, size_t booksize)
static const char *const mon_book_name[]
int buf_overflow(const char *buf1, const char *buf2, size_t bufsize)
void describe_resistance(const object *op, int newline, char *buf, size_t size)
struct titlestruct * next
struct titleliststruct titlelist
#define MSG_TYPE_PAPER_LETTER_NEW_1
#define MSG_TYPE_PAPER_SCROLL_MAGIC
object * create_archetype(const char *name)
artifactlist * find_artifactlist(int type)
#define MSG_TYPE_PAPER_SCROLL_NEW_1
#define MSG_TYPE_BOOK_SPELL_SORCERER
#define FLAG_UNAGGRESSIVE
struct namebytype arttypename
static const uint32 spellpathdef[NRSPELLPATHS]
struct linked_char * next
#define MSG_TYPE_PAPER_SCROLL_NEW_2
int strtoint(const char *buf)
godlink * get_rand_god(void)
static int need_to_write_bookarchive
struct titleliststruct * next
#define MSG_TYPE_CARD_SIMPLE_1
#define MSG_TYPE_PAPER_NOTE_3
#define MSG_TYPE_SIGN_DIR_BOTH
#define MSG_TYPE_CARD_SIMPLE_2
void tailor_readable_ob(object *book, int msg_type)
const object * pntr_to_god_obj(godlink *godlnk)
static const char *const book_author[]
#define MSG_TYPE_MONUMENT_STONE_1
#define arraysize(arrayname)
static const char *const gods_author[]
static titlelist * booklist
static void add_book(title *book, int type, const char *fname, int lineno)
#define QUERY_FLAG(xyz, p)
EXTERN const char *const attacktype_desc[NROFATTACKS]
static void add_author(object *op, int msgtype)
#define MSG_TYPE_PAPER_SCROLL_OLD_1
object * get_object(void)
#define MSG_TYPE_SIGN_BASIC
#define MSG_TYPE_CARD_STRANGE_3
#define MSGTYPE_SPELLPATH
#define MSG_TYPE_PAPER_LETTER_NEW_2
static const char *const mon_author[]
static int unique_book(const object *book, int msgtype)
#define MSG_TYPE_MONUMENT_STONE_3
sint16 resist[NROFATTACKS]
#define MSG_TYPE_MONUMENT_WALL_1
static const char *const gods_book_name[]
#define MSG_TYPE_PAPER_ENVELOPE_2
#define DESCRIBE_PATH_SAFE(retbuf, variable, name, len, maxlen)
#define MSG_TYPE_MONUMENT_WALL_2
#define MSG_TYPE_BOOK_SPELL_PYRO
int snprintf(char *dest, int max, const char *format,...)
static const char *const art_author[]
static titlelist * get_empty_booklist(void)
static const readable_message_type readable_message_types[]
#define MSG_TYPE_BOOK_CLASP_2
static const char *const formula_author[]
static char * god_info_msg(int level, char *retbuf, size_t booksize)
#define MSG_TYPE_BOOK_ELEGANT_1
int book_overflow(const char *buf1, const char *buf2, size_t booksize)
void free_all_readable(void)
struct recipestruct * next
static const int max_titles[6]
static const char *const path_author[]
void write_book_archive(void)
static const char *const light_book_name[]
#define MSG_TYPE_CARD_SIMPLE_3
#define MSG_TYPE_BOOK_QUARTO_1
void describe_item(const object *op, const object *owner, char *retbuf, size_t size)
static objectlink * first_mon_info
sstring add_string(const char *str)
struct titlestruct * first_book
static linked_char * first_msg
static void change_book(object *book, int msgtype)
static void init_mon_info(void)
const readable_message_type * get_readable_message_type(object *readable)
#define MSG_TYPE_PAPER_NOTE_2
#define MSG_TYPE_CARD_ELEGANT_3
#define MSG_TYPE_MONUMENT_WALL_3
void LOG(LogLevel logLevel, const char *format,...)
#define MSG_TYPE_CARD_MONEY_2
#define MSG_TYPE_BOOK_ELEGANT_2
#define MSG_TYPE_PAPER_SCROLL_OLD_2
#define MSG_TYPE_MONUMENT_STATUE_3
#define MSG_TYPE_MONUMENT_GRAVESTONE_1
#define MSG_TYPE_MONUMENT
#define MSG_TYPE_PAPER_NOTE_1
static const char *const formula_book_name[]
static char * mon_info_msg(int level, char *buf, size_t booksize)
void copy_object(object *op2, object *op)
void query_name(const object *op, char *buf, size_t size)
void free_object(object *ob)
static int nstrtok(const char *buf1, const char *buf2)
static char * mon_desc(const object *mon, char *buf, size_t size)
static const char *const book_descrpt[]
static void new_text_name(object *book, int msgtype)
static const char *const art_book_name[]
#define MSG_TYPE_BOOK_SPELL_SUMMONER
EXTERN archetype * first_archetype
FILE * open_and_uncompress(const char *name, int flag, int *compressed)
#define MSG_TYPE_CARD_MONEY_1
struct recipestruct * items
recipelist * get_formulalist(int i)
#define MSG_TYPE_PAPER_ENVELOPE_1
struct artifactstruct * next
#define MSG_TYPE_CARD_ELEGANT_1
static title * get_empty_book(void)