/**
* This handler object deals with all the books that have been published.
* It keeps a save file of every book and a current book number.
* It will allow for easy finding again of preprinted books and for the
* easy removal of any books that happen to contain things like quest
* solutions and stuff.
*
* @author Pinkfish
* @started Sun Feb 1 20:24:33 CST 1998
* @see /std/book.c
* @see /std/print_shop.c
*/
#include <book_handler.h>
#include <language.h>
#define SAVE_DIR "/save/book_handler/"
#define SAVE_FILE (SAVE_DIR "main_save")
#define OWNER_INDEX "owner"
#define PAGES_INDEX "pages"
int current_book_number;
mapping banished_books;
int compare_page(object page1, object page2);
void load_it();
void save_it();
int check_book_same(object book, int num);
protected string *query_pages(object book);
int compare_pages(string *pages1, string *pages2);
string *query_book_pages(int book_num);
void create() {
banished_books = ([ ]);
seteuid(getuid());
load_it();
} /* create() */
/**
* This tests to see if the given book number exists.
* @param book_num the number to test.
* @return 1 if it exists, 0 if it does not.
*/
int query_book_exists(int book_num) {
return unguarded((: file_size(SAVE_DIR + $(book_num) + ".o") :)) > 0;
} /* query_book_exists() */
/**
* Adds a newly minted book into our nice list of stuff. This returns the
* book number for this book. You can use this to add a book if you already
* know its book number, if it does not match to the saved book number then
* it will return a new number. If it does match it will return the
* same number.
* @param book the book to add
* @param num the possible book number it already has
* @see check_book_same()
*/
int add_book(object book, int num, string pl_name) {
string *stuff;
mapping bing;
if (num) {
if (check_book_same(book, num)) {
return num;
}
}
/* Make sure if the save file gets stuffed up we don't overwrite things. */
while (query_book_exists(current_book_number)) {
current_book_number++;
}
stuff = query_pages(book);
bing = ([ OWNER_INDEX : pl_name, PAGES_INDEX : stuff ]);
unguarded( (: write_file(SAVE_DIR + current_book_number + ".o",
save_variable($(bing))) :) );
num = current_book_number++;
save_it();
return num;
} /* add_book() */
/**
* Checks to see if the passed in book is the same as the current book
* number that is set on it. We only look at the text and ignore the
* type and language with which it is written.
* @param book the book to check
* @param num the book number to check against
* @see compare_pages()
* @see add_book()
*/
int check_book_same(object book, int num) {
string *bing;
string *fluff;
int old_open_page;
int same;
old_open_page = book->query_open_page();
same = 0;
if (query_book_exists(num) > 0) {
bing = query_book_pages(num);
fluff = query_pages(book);
if (compare_pages(bing, fluff) > 90) {
same = 1;
}
} else {
same = 0;
}
book->set_open_page(old_open_page);
return same;
} /* check_book_same() */
/**
* This method returns the pages associated with the book of a given
* number.
* @return the pages for the book
* @param book_num the book number to get the pages for
* @see query_book_owner()
*/
string *query_book_pages(int book_num) {
mapping bing;
string tmp;
tmp = unguarded((: read_file(SAVE_DIR + $(book_num) + ".o") :));
if (tmp) {
bing = restore_variable(tmp);
return bing[PAGES_INDEX];
}
return 0;
} /* query_book_pages() */
/**
* This method returns the owner associated with the book of a given
* number.
* @return the owner of the book
* @param book_num the book number to get the pages for
* @see query_book_pages()
*/
string query_book_owner(int book_num) {
mapping bing;
string tmp;
tmp = unguarded((: read_file(SAVE_DIR + $(book_num) + ".o") :));
if (tmp) {
bing = restore_variable(tmp);
return bing[OWNER_INDEX];
}
return 0;
} /* query_book_owner() */
/**
* This method returns the array of useful pages in a book. It removes
* torn out pages and pages which are added by specific things in the
* game, like the print shop adding a fly leaf. It just returns the text
* for the pages, since this is what we are interested in.
* @param book the book to get the pages from
* @return the array of pages
*/
string *query_pages(object book) {
int i;
string *ret;
mixed *stuff;
mixed *group;
string text;
int old_open_page;
object ob;
ret = ({ });
old_open_page = book->query_open_page();
for (i = 0; i < book->query_num_pages(); i++) {
book->set_open_page(i);
ob = book->query_current_page();
/* Make sure it is not torn out and that it is not auto generated. */
if (!book->is_current_page_torn_out() &&
!ob->query_property(BH_IGNORE_PAGE)) {
stuff = ob->query_read_mess();
text = "";
foreach (group in stuff) {
text += group[READ_MESS];
}
ret += ({ text });
}
}
book->set_open_page(old_open_page);
return ret;
} /* query_pages() */
/**
* This method will try and figure out the percentage changed between the
* two page arrays.
* @param pages1 the first page array
* @param pages2 the second page array
* @return the percentage the same
*/
int compare_pages(string *pages1, string *pages2) {
int no_chars;
int no_same;
int pos;
int start;
string page;
string *tmp;
pos = 0;
if (sizeof(pages1) > sizeof(pages2)) {
tmp = pages1;
pages1 = pages2;
pages2 = tmp;
}
/* Now we go through the smaller array... */
foreach (page in pages1) {
/*
* Ok, now see if we can find where this page might start in the
* other book.
*
* We will assume that all books will start the same. Therefor
* if we cannot find a match for the first page... The rest of the
* book does not match. We assume that the one stored in the
* book handler is the complete one.
*/
pos = 0;
do {
start = strsrch(page, pages2[pos]);
if (start == -1) {
start = strsrch(pages2[pos], page);
if (start == -1) {
pos++;
} else {
no_same += strlen(page);
}
} else {
no_same += strlen(pages2[pos]);
}
} while ((start == -1) && (pos < sizeof(pages2)));
no_chars += strlen(page);
}
/* Calculate the percentage the same and return it. */
if (no_chars > 0) {
return (no_same * 100) / no_chars;
}
return 0;
} /* compare_pages() */
/**
* Compares the open pages of two books to see if the text is the
* same. It ignores language and style of writing. This would also
* work on two pieces of paper.
* @param page1 the first book
* @param page2 the second book
* @see check_book_same()
* @see add_book()
*/
int compare_page(string page1, string page2) {
mixed *stuff1;
mixed *stuff2;
string text1;
string text2;
int i;
stuff2 = page2->query_read_mess();
text1 = "";
for (i = 0; i < sizeof(stuff1); i++) {
text1 += stuff1[READ_MESS];
}
text2 = "";
for (i = 0; i < sizeof(stuff2); i++) {
text2 += stuff2[READ_MESS];
}
return (text1 == text2);
} /* compare_page() */
/**
* This method banishes a book number for a certain reason.
* @param book_num the book number to banish
* @param reason the reason it was banished
* @return 1 on success and 0 on failure.
* @see query_banished_book()
* @see query_all_banished_books()
*/
int add_banished_book(int book_num, string reason) {
if (!stringp(reason) || !intp(book_num)) {
/* Need a reason. */
return 0;
}
if (!query_book_exists(book_num)) {
/* Does not exist. */
return 0;
}
banished_books[book_num] = reason;
} /* banish_book_num() */
/**
* This method returns the banish string for the book.
* @param book_num the book number to check
* @return the banish reason, or 0 if none
* @see add_banished_book()
* @see query_all_banished_books()
*/
string query_banished_book(int book_num) {
return banished_books[book_num];
} /* query_banished_book() */
/**
* This method returns all the banished books. The keys are the
* numbers which are banished and the values are the reason for
* the banishment.
* @return the banished books mapping
* @see add_banished_book()
* @see query_banished_book()
*/
mapping query_all_banished_books() {
return banished_books;
} /* query_all_banished_books() */
/**
* Saves the current state information to the save file.
* @see save_it()
*/
void save_it() {
unguarded((: save_object(SAVE_FILE) :));
} /* save_it() */
/**
* Loads the state information from the save file.
* @see load_it()
*/
void load_it() {
unguarded((: restore_object(SAVE_FILE) :));
if (!current_book_number) {
current_book_number = 1;
}
if (!banished_books) {
banished_books = ([ ]);
}
} /* load_it() */