skylib_fluffos_v3/
skylib_fluffos_v3/bin/
skylib_fluffos_v3/bin/db/
skylib_fluffos_v3/fluffos-2.9-ds2.04/
skylib_fluffos_v3/fluffos-2.9-ds2.04/ChangeLog.old/
skylib_fluffos_v3/fluffos-2.9-ds2.04/Win32/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/
skylib_fluffos_v3/fluffos-2.9-ds2.04/compat/simuls/
skylib_fluffos_v3/fluffos-2.9-ds2.04/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/clone/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/command/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/data/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/etc/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/include/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/inherit/master/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/log/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/compiler/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/efuns/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/single/tests/operators/
skylib_fluffos_v3/fluffos-2.9-ds2.04/testsuite/u/
skylib_fluffos_v3/fluffos-2.9-ds2.04/tmp/
skylib_fluffos_v3/fluffos-2.9-ds2.04/windows/
skylib_fluffos_v3/mudlib/
skylib_fluffos_v3/mudlib/cmds/
skylib_fluffos_v3/mudlib/cmds/admin/
skylib_fluffos_v3/mudlib/cmds/guild-race/
skylib_fluffos_v3/mudlib/cmds/living/broken/
skylib_fluffos_v3/mudlib/cmds/player/group_cmds/
skylib_fluffos_v3/mudlib/cmds/playtester/
skylib_fluffos_v3/mudlib/d/admin/
skylib_fluffos_v3/mudlib/d/admin/room/
skylib_fluffos_v3/mudlib/d/admin/room/we_care/
skylib_fluffos_v3/mudlib/d/admin/save/
skylib_fluffos_v3/mudlib/d/admin/text/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/buildings/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/map/
skylib_fluffos_v3/mudlib/d/learning/TinyTown/roads/
skylib_fluffos_v3/mudlib/d/learning/chars/
skylib_fluffos_v3/mudlib/d/learning/functions/
skylib_fluffos_v3/mudlib/d/learning/handlers/
skylib_fluffos_v3/mudlib/d/learning/help_topics/
skylib_fluffos_v3/mudlib/d/learning/help_topics/npcs/
skylib_fluffos_v3/mudlib/d/learning/help_topics/objects/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rcs_demo/RCS/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/crowd/
skylib_fluffos_v3/mudlib/d/learning/help_topics/rooms/situations/
skylib_fluffos_v3/mudlib/d/learning/save/
skylib_fluffos_v3/mudlib/d/learning/school/
skylib_fluffos_v3/mudlib/d/learning/school/add_sc/
skylib_fluffos_v3/mudlib/d/learning/school/characters/
skylib_fluffos_v3/mudlib/d/learning/school/general/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/basic_commands/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/edtutor/
skylib_fluffos_v3/mudlib/d/learning/school/getting-started/unix_tutor/
skylib_fluffos_v3/mudlib/d/learning/school/items/
skylib_fluffos_v3/mudlib/d/learning/school/npc_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/room_basic/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/situations/
skylib_fluffos_v3/mudlib/d/learning/school/room_school/terrain_tutor/
skylib_fluffos_v3/mudlib/d/learning/text/
skylib_fluffos_v3/mudlib/d/liaison/
skylib_fluffos_v3/mudlib/d/mudlib/
skylib_fluffos_v3/mudlib/d/mudlib/changes/
skylib_fluffos_v3/mudlib/d/playtesters/
skylib_fluffos_v3/mudlib/d/playtesters/effects/
skylib_fluffos_v3/mudlib/d/playtesters/handlers/
skylib_fluffos_v3/mudlib/d/playtesters/items/
skylib_fluffos_v3/mudlib/d/sage/
skylib_fluffos_v3/mudlib/doc/
skylib_fluffos_v3/mudlib/doc/creator/
skylib_fluffos_v3/mudlib/doc/driver/
skylib_fluffos_v3/mudlib/doc/driver/efuns/arrays/
skylib_fluffos_v3/mudlib/doc/driver/efuns/buffers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/calls/
skylib_fluffos_v3/mudlib/doc/driver/efuns/compile/
skylib_fluffos_v3/mudlib/doc/driver/efuns/filesystem/
skylib_fluffos_v3/mudlib/doc/driver/efuns/floats/
skylib_fluffos_v3/mudlib/doc/driver/efuns/functions/
skylib_fluffos_v3/mudlib/doc/driver/efuns/general/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mappings/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mixed/
skylib_fluffos_v3/mudlib/doc/driver/efuns/mudlib/
skylib_fluffos_v3/mudlib/doc/driver/efuns/numbers/
skylib_fluffos_v3/mudlib/doc/driver/efuns/parsing/
skylib_fluffos_v3/mudlib/doc/login/
skylib_fluffos_v3/mudlib/doc/lpc/basic_manual/
skylib_fluffos_v3/mudlib/doc/lpc/intermediate/
skylib_fluffos_v3/mudlib/doc/new/add_command/
skylib_fluffos_v3/mudlib/doc/new/events/
skylib_fluffos_v3/mudlib/doc/new/handlers/
skylib_fluffos_v3/mudlib/doc/new/living/race/
skylib_fluffos_v3/mudlib/doc/new/living/spells/
skylib_fluffos_v3/mudlib/doc/new/object/
skylib_fluffos_v3/mudlib/doc/new/player/
skylib_fluffos_v3/mudlib/doc/new/room/guild/
skylib_fluffos_v3/mudlib/doc/new/room/outside/
skylib_fluffos_v3/mudlib/doc/new/room/storeroom/
skylib_fluffos_v3/mudlib/doc/object/
skylib_fluffos_v3/mudlib/doc/playtesters/
skylib_fluffos_v3/mudlib/doc/policy/
skylib_fluffos_v3/mudlib/doc/weapons/
skylib_fluffos_v3/mudlib/global/
skylib_fluffos_v3/mudlib/global/creator/
skylib_fluffos_v3/mudlib/handlers/
skylib_fluffos_v3/mudlib/include/casino/
skylib_fluffos_v3/mudlib/include/cmds/
skylib_fluffos_v3/mudlib/include/effects/
skylib_fluffos_v3/mudlib/include/npc/
skylib_fluffos_v3/mudlib/include/room/
skylib_fluffos_v3/mudlib/include/shops/
skylib_fluffos_v3/mudlib/net/daemon/
skylib_fluffos_v3/mudlib/net/daemon/chars/
skylib_fluffos_v3/mudlib/net/inherit/
skylib_fluffos_v3/mudlib/net/obj/
skylib_fluffos_v3/mudlib/net/obj/BACKUPS/
skylib_fluffos_v3/mudlib/obj/amulets/
skylib_fluffos_v3/mudlib/obj/armours/plate/
skylib_fluffos_v3/mudlib/obj/b_day/
skylib_fluffos_v3/mudlib/obj/clothes/transport/horse/
skylib_fluffos_v3/mudlib/obj/faith/symbols/
skylib_fluffos_v3/mudlib/obj/fungi/
skylib_fluffos_v3/mudlib/obj/gatherables/
skylib_fluffos_v3/mudlib/obj/instruments/
skylib_fluffos_v3/mudlib/obj/media/
skylib_fluffos_v3/mudlib/obj/misc/player_shop/
skylib_fluffos_v3/mudlib/obj/monster/godmother/
skylib_fluffos_v3/mudlib/obj/monster/transport/
skylib_fluffos_v3/mudlib/obj/rings/
skylib_fluffos_v3/mudlib/obj/scabbards/
skylib_fluffos_v3/mudlib/obj/spells/
skylib_fluffos_v3/mudlib/obj/stationery/
skylib_fluffos_v3/mudlib/obj/stationery/envelopes/
skylib_fluffos_v3/mudlib/obj/toys/
skylib_fluffos_v3/mudlib/obj/vessels/
skylib_fluffos_v3/mudlib/obj/weapons/axes/
skylib_fluffos_v3/mudlib/obj/weapons/chains/
skylib_fluffos_v3/mudlib/obj/weapons/maces/BACKUPS/
skylib_fluffos_v3/mudlib/save/autodoc/
skylib_fluffos_v3/mudlib/save/book_handler/
skylib_fluffos_v3/mudlib/save/books/history/calarien/
skylib_fluffos_v3/mudlib/save/mail/
skylib_fluffos_v3/mudlib/save/new_soul/data/
skylib_fluffos_v3/mudlib/save/parcels/
skylib_fluffos_v3/mudlib/save/playerinfo/
skylib_fluffos_v3/mudlib/save/players/d/
skylib_fluffos_v3/mudlib/save/players/s/
skylib_fluffos_v3/mudlib/save/random_names/
skylib_fluffos_v3/mudlib/save/random_names/data/
skylib_fluffos_v3/mudlib/save/terrains/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_desert/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_grassy_field/
skylib_fluffos_v3/mudlib/save/terrains/tutorial_mountain/
skylib_fluffos_v3/mudlib/save/todo_lists/
skylib_fluffos_v3/mudlib/secure/
skylib_fluffos_v3/mudlib/secure/cmds/admin/
skylib_fluffos_v3/mudlib/secure/cmds/lord/
skylib_fluffos_v3/mudlib/secure/config/
skylib_fluffos_v3/mudlib/secure/handlers/autodoc/
skylib_fluffos_v3/mudlib/secure/handlers/intermud/
skylib_fluffos_v3/mudlib/secure/include/global/
skylib_fluffos_v3/mudlib/secure/save/
skylib_fluffos_v3/mudlib/secure/save/handlers/
skylib_fluffos_v3/mudlib/secure/std/
skylib_fluffos_v3/mudlib/secure/std/classes/
skylib_fluffos_v3/mudlib/secure/std/modules/
skylib_fluffos_v3/mudlib/std/creator/
skylib_fluffos_v3/mudlib/std/dom/
skylib_fluffos_v3/mudlib/std/effects/
skylib_fluffos_v3/mudlib/std/effects/external/
skylib_fluffos_v3/mudlib/std/effects/fighting/
skylib_fluffos_v3/mudlib/std/effects/magic/
skylib_fluffos_v3/mudlib/std/effects/magic/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/other/BACKUPS/
skylib_fluffos_v3/mudlib/std/effects/priest/
skylib_fluffos_v3/mudlib/std/effects/room/
skylib_fluffos_v3/mudlib/std/environ/
skylib_fluffos_v3/mudlib/std/guilds/
skylib_fluffos_v3/mudlib/std/guilds/old/
skylib_fluffos_v3/mudlib/std/languages/
skylib_fluffos_v3/mudlib/std/liquids/
skylib_fluffos_v3/mudlib/std/npc/
skylib_fluffos_v3/mudlib/std/npc/goals/
skylib_fluffos_v3/mudlib/std/npc/goals/basic/
skylib_fluffos_v3/mudlib/std/npc/goals/misc/
skylib_fluffos_v3/mudlib/std/npc/plans/
skylib_fluffos_v3/mudlib/std/npc/plans/basic/
skylib_fluffos_v3/mudlib/std/npc/types/
skylib_fluffos_v3/mudlib/std/npc/types/helper/
skylib_fluffos_v3/mudlib/std/npcs/
skylib_fluffos_v3/mudlib/std/outsides/
skylib_fluffos_v3/mudlib/std/races/shadows/
skylib_fluffos_v3/mudlib/std/room/basic/BACKUPS/
skylib_fluffos_v3/mudlib/std/room/basic/topography/
skylib_fluffos_v3/mudlib/std/room/controller/
skylib_fluffos_v3/mudlib/std/room/inherit/topography/
skylib_fluffos_v3/mudlib/std/room/topography/area/
skylib_fluffos_v3/mudlib/std/room/topography/iroom/
skylib_fluffos_v3/mudlib/std/room/topography/milestone/
skylib_fluffos_v3/mudlib/std/shadows/curses/
skylib_fluffos_v3/mudlib/std/shadows/disease/
skylib_fluffos_v3/mudlib/std/shadows/fighting/
skylib_fluffos_v3/mudlib/std/shadows/healing/
skylib_fluffos_v3/mudlib/std/shadows/magic/
skylib_fluffos_v3/mudlib/std/shadows/poison/
skylib_fluffos_v3/mudlib/std/shadows/room/
skylib_fluffos_v3/mudlib/std/shops/controllers/
skylib_fluffos_v3/mudlib/std/shops/objs/
skylib_fluffos_v3/mudlib/std/shops/player_shop/
skylib_fluffos_v3/mudlib/std/socket/
skylib_fluffos_v3/mudlib/std/soul/d/
skylib_fluffos_v3/mudlib/std/soul/e/
skylib_fluffos_v3/mudlib/std/soul/i/
skylib_fluffos_v3/mudlib/std/soul/j/
skylib_fluffos_v3/mudlib/std/soul/k/
skylib_fluffos_v3/mudlib/std/soul/l/
skylib_fluffos_v3/mudlib/std/soul/n/
skylib_fluffos_v3/mudlib/std/soul/o/
skylib_fluffos_v3/mudlib/std/soul/q/
skylib_fluffos_v3/mudlib/std/soul/r/
skylib_fluffos_v3/mudlib/std/soul/u/
skylib_fluffos_v3/mudlib/std/soul/v/
skylib_fluffos_v3/mudlib/std/soul/y/
skylib_fluffos_v3/mudlib/std/soul/z/
skylib_fluffos_v3/mudlib/std/stationery/
skylib_fluffos_v3/mudlib/w/
skylib_fluffos_v3/mudlib/w/default/
skylib_fluffos_v3/mudlib/w/default/armour/
skylib_fluffos_v3/mudlib/w/default/clothes/
skylib_fluffos_v3/mudlib/w/default/item/
skylib_fluffos_v3/mudlib/w/default/npc/
skylib_fluffos_v3/mudlib/w/default/room/
skylib_fluffos_v3/mudlib/w/default/weapon/
skylib_fluffos_v3/mudlib/www/
skylib_fluffos_v3/mudlib/www/java/
skylib_fluffos_v3/mudlib/www/secure/
skylib_fluffos_v3/mudlib/www/secure/lpc/advanced/
skylib_fluffos_v3/mudlib/www/secure/lpc/intermediate/
skylib_fluffos_v3/win32/
/**
 * A nice book object.  A book will be a collection of pages.
 * You can tear pages out of a book, you can add pages (though adding
 * a page isnt overly useful, unless you bind it in of course).
 *<p>
 * Each page is an object.  Pages that are torn out are handled
 * as empty spots in the array.
 *<p>
 * @change 26-Feb-96 Jeremy
 * I took out the "my book" checks in test_add() and test_remove()
 * because they were keeping written pages from loading.  If
 * anyone knows why the checks were necessary, let me know.
 * @change 25-Aug-96 Jeremy
 * Changed test_add() so that it won't add things held by players.
 * This is because if they "put" something in the book, it's inaccessible
 * (maybe this is why pages had the "my book" property?  I like this
 * solution better, but not much).
 * @author Pinkfish
 */

#include <move_failures.h>
#include <player.h>

inherit OBJECT_OBJ;

private mixed _pages;
private string _default_page_object;
private object _def_p_obj;
/* Open_page set to 0 means closed. */
private int _open_page;
private int _book_num;
/*
 * If this is set, we ignore the flag and only print the real
 * short of the book.
 */
private int _ignore_open_page;
/*
 * This should be used in conjuction with created books
 * that yuou wish the contents to update when changed.
 */
private int _ignore_saved_pages;
private nosave object _player;

protected int do_open(int page);
protected int do_tear(int number);
protected int do_turn(int number);
protected int do_close();
object create_default_page_object();
private void replace_page(mixed page, int pos);

void create() {
  _pages = ({ });
  _default_page_object = PAPER_OBJ;
  load_object(_default_page_object);
  _def_p_obj = find_object(_default_page_object);
  ::create();
} /* create() */

/**
 * Tells us if this is a book object.
 * @return always returns 1
 */
int query_book() { return 1; }

/**
 * Adds the commands onto the player.  The commands are "read", "open",
 * "tear", "turn" and "close".
 * @ignore yes
 */
void init() {
  add_command("open", "<direct:object>", (: do_open(1) :));
  add_command("open", "<direct:object> to [page] <number>",
              (: do_open($4[1]) :));
  add_command("tear", "page from <direct:object>", (: do_tear(1) :));
  add_command("tear", "[all] pages from <direct:object>", (: do_tear(0) :));
  add_command("tear", "<number> [of] pages from <direct:object>",
              (: do_tear($4[0]) :));
  add_command("rip", "page from <direct:object>", (: do_tear(1) :));
  add_command("rip", "<number> [of] pages from <direct:object>",
              (: do_tear($4[0]) :));
  add_command("rip", "[all] pages from <direct:object>", (: do_tear(0) :));
  add_command("turn", "[a] page of <direct:object>", (: do_turn(1) :));
  add_command("turn", "<number> pages of <direct:object>",
              (: do_turn($4[0]) :));
  add_command("turn", "<direct:object> to [page] <number>",
              (: do_open($4[1]) :) );
  add_command("turn", "to page <number> of <direct:object>",
              (: do_open($4[0]) :) );
  add_command("close", "<direct:object>", (: do_close() :));
} /* init() */

/**
 * @ignore yes
 */
int add_weight( int number ) {
   adjust_weight( number );
   return 1;
} /* add_weight() */

/**
 * To see if things can be added to us.  This has a few nasty
 * cludges in it to stop a few things.
 * @see /std/basic/misc
 * @param ob the object being added
 * @param flag the flag sent to this function
 * @return 1 if it can be added, 0 if it cannot
 * @ignore
 */
int test_add(object ob, int flag) {
  return (object)ob->query_property("my book") == TO;
  // This is a kludge to keep people from putting things in the book.
  // It's not foolproof, but it should do until I think of a better way.
/*
  if (!environment(ob) || !living(environment(ob)))
    return 1;
  return 0;
 */
} /* test_add() */

/**
 * To check to see if things can be removed from us.
 * @see /std/basic/misc
 * @param ob the object being removed
 * @param flag the flag sent to the function
 * @param dest where it is going to
 * @return 1 if it can be removed, 0 if it cannot
 * @ignore
 */
int test_remove( object ob, int flag, mixed dest ) {
  return ob->query_property("my book") != TO;
  //return 1;
} /* test_remove() */

/**
 * Set the number of pages in the book.  If there are too many pages
 * in the book, then pages are removed from the top to create the
 * correct size and if there are too few pages then pages are
 * added onto the end of the pages array.
 * @param no the number of pages
 * @see query_pages()
 * @see query_num_pages()
 */
void set_no_pages(int no) {
  int i;
  int siz;

  siz = sizeof(_pages);
  if (no < siz) { /* removeing pages?  Oh well, if you insist. */
    for (i = no; i < siz; i++) {
      if (objectp(_pages[i])) {
        _pages[i]->dest_me();
      }
    }
    _pages = _pages[0..no-1];
    if (_open_page >= no) {
      _open_page = no;
    }
  } else {
    /* Adding pages, more normal... */
    _pages = _pages + allocate(no-siz);
    for (i=siz;i<no;i++) {
      /* Set them to 1 and only make them real if someone wants them. */
      _pages[i] = 1;
    }
  }
} /* set_no_pages() */

/**
 * Returns the pages array.
 * @return the array containing the pages information
 */
object *query_pages() { return _pages; }

/**
 * Sets the currently open page.  This does all the magic needed to make
 * the book appear as if it is the currently opened page.  If the open
 * page is 0 then the book is closed.  If it is out of the upper
 * bound then the book is opened to the last page.
 * @param i the page to open to
 * @see query_open_page()
 * @see query_current_page()
 */
void set_open_page(int i) {
  /* Valid page or already there. */
  if (i < 0 || i == _open_page) {
     return ;
  }

  if (!_open_page && i) {
    add_alias("page");
    add_plural("pages");
  }

  if (i > sizeof(_pages)) {
    _open_page = sizeof(_pages);
  } else {
    _open_page = i;
  }

  if (!_open_page) {
    remove_alias("page");
    remove_plural("pages");
  }
} /* set_open_page() */

/**
 * What is the current open page.  Returns 0 if the book is not
 * open.
 * @return the current open page
 * @see set_open_page()
 * @see query_current_page()
 */
int query_open_page() {
   return _open_page;
} /* query_open_page() */

/**
 * This method checks to see if the current page is torn out.
 * @return 1 if torn out, 0 if not
 * @see query_current_page()
 * @see query_open_page()
 * @see is_page_torn_out()
 */
int is_current_page_torn_out() {
   if (!_open_page) {
      /* The cover cannot be torn out. */
      return 0;
   }
   if ( !_pages ) {
      return 0;
   }

   if (!_pages[_open_page-1]) {
      return 1;
   }
   return 0;
} /* is_current_page_torn_out() */

/**
 * This method checks to see if the specified page is torn out.
 * @param page the page number to check
 * @return 1 if it is torn out, - if not
 * @see is_current_page_torn_out()
 */
int is_page_torn_out(int page) {
   if (page < 1 || page > sizeof(_pages)) {
      return 0;
   }

   if (!_pages[page - 1]) {
      return 1;
   }
   return 0;
} /* is_page_torn_out() */

/**
 * Returns the object associated with the current open page.  If the
 * page does not actualy exist yet then the default base object
 * is returned.  This object should be handled carefully...  If the
 * page is torn out then the next readable page is returned or
 * 0 is returned.
 * @return the current page object
 * @see query_current_page_clone()
 * @see set_open_page()
 * @see query_open_page()
 * @see query_current_page_clone()
 */
object query_current_page() {
   int i;

   if (!_open_page) {
      return TO; /* The book itself... */
   }
   for (i = _open_page - 1; i < sizeof(_pages); i++) {
      if (_pages[i]) {
         if (objectp(_pages[i])) {
            return _pages[i];
         } else {
            return _def_p_obj;
         }
      }
   }
   return 0;
} /* query_current_page() */

/**
 * This function makes sure the page actually
 * exists.  If it does not exist, then it will clone one
 * up for us.  This one should be used as you will not end up with the
 * base object in this case.  If you are planning to modify the page,
 * then use this call.
 * @see query_current_page()
 * @return the object of the current page
 */
object query_current_page_clone() {
  if (_open_page) {
    if (!_pages[_open_page-1]) {
      return 0;
    } else if (objectp(_pages[_open_page-1])) {
      return _pages[_open_page-1];
    } else {
      replace_page(create_default_page_object(), _open_page - 1);
      return _pages[_open_page-1];
    }
  } else {
    return TO;
  }
} /* query_current_page_clone() */

/**
 * This method checks to see if the page is still the default page object
 * or if it is something else altogether.
 * @return 1 if it is the default page object, 0 if not
 */
int is_default_page(int num) {
   if (num > 0 && num <= sizeof(_pages)) {
      if (_pages[num - 1] &&
          !objectp(_pages[num - 1])) {
         return 1;
      }
   }
   return 0;
} /* is_default_page() */

/**
 * This method returns the contents of the selected page.  The number
 * must be greator than 0.  This will return the exact value of the
 * page, it will not search for non-torn out pages.  Becare with
 * the return value of this as the default page object might be
 * returned if the page does not actually exist.  If you need a
 * real object remember to use the clone version.
 * @param num the page to return
 * @return 0 on failure or if the page is torn out, the object on success
 */
object query_selected_page(int num) {
   if (!intp(num) || num <= 0 || num > sizeof(_pages)) {
      return 0;
   }

   if (_pages[num - 1]) {
      if (objectp(_pages[num - 1])) {
         return _pages[num - 1];
      } else {
         return _def_p_obj;
      }
   }
   return 0;
} /* query_selected_page() */

/**
 * This method returns the contents of the selected page, if a default
 * object is returned a real clone for the page is created instead.
 * @param num the page to return
 * @return 0 on failure or if the page is torn out, the object on success
 */
object query_selected_page_clone(int num) {
   if (!intp(num) || num <= 0 || num > sizeof(_pages)) {
      return 0;
   }

   if (_pages[num - 1]) {
      if (objectp(_pages[num - 1])) {
         return _pages[num - 1];
      } else {
         replace_page(create_default_page_object(), num - 1);
         return _pages[num - 1];
      }
   }
   return 0;
} /* query_selected_page_clone() */

/**
 * This method tears the current page out of the book and returns it
 * to us.  This object will be moved into the destination so that it is
 * no longer inside us.  If it cannot be moved of the page has already
 * been remove then the function will return 0.
 * @param dest the destination to move the page to
 * @return the torn out page, or 0 on failure
 */
object tear_current_page_out(object dest) {
  object page;

  if (is_current_page_torn_out()) {
    /* Too late... */
    return 0;
  }

  page = query_current_page_clone();
  // Fiddle with the properties so the page is moveable.
  page->remove_property("my book");
  if (page && page->move(dest) == MOVE_OK) {
    _pages[_open_page-1] = 0;
    return page;
  }
  page->add_property("my book", TO);
  return 0;
} /* tear_current_page_out() */

/**
 * This method adds a new page in after the selected page.  The pages
 * are numbered from 1, so adding a page after page 0 will place a
 * page on the start and after the last page onto the end.
 * @param page the page to add
 * @param after the page to add it after
 * @return 1 on success, 0 on failure
 * @see query_current_page()
 * @see query_num_pages()
 */
int add_page_after(object page, int after) {
   if (after < 0 || after > sizeof(_pages) + 1 ||
       !objectp(page) || !intp(after)) {
      return 0;
   }
   _pages = _pages[0..after - 1] + ({ 1 }) + _pages[after..];
   replace_page(page, after);
   return 1;
} /* add_page_after() */

/**
 * This is the internal function used to replace pages.  This will do
 * all the cleaning up of the pages needed to make this work
 * properly.
 * @param page the page to replace it with
 * @param pos the position to replace
 */
private void replace_page(mixed page, int pos) {
   if (objectp(_pages[pos]) && _pages[pos] != page) {
      _pages[pos]->dest_me();
   }
   if (objectp(page)) {
      page->add_property("my book", TO);
      page->move(TO);
   }
   _pages[pos] = page;
} /* replace_page() */

/**
 * This method replaces the selected page with a new page.  The old page
 * is dested if it can be and replaced with a nice shiny new page object.
 * @param page the page to replace with
 * @param num the page number to replace
 * @return 1 on success, 0 on failure
 * @see add_page_after()
 */
int replace_page_with(object page, int num) {
   if (num < 1 || num > sizeof(_pages) ||
       !objectp(page) || !intp(num)) {
      return 0;
   }

   replace_page(page, num - 1);
} /* replace_page_with() */

/**
 * This method makes the selected page blank.  It defaults it back to a
 * default page object as if the book had just been created.
 * @param num the page to make blank
 * @see replace_page_with()
 * @see add_page_after()
 * @see add_blank_page_after()
 */
int make_page_blank(int num) {
   if (num < 1 || num > sizeof(_pages) || !intp(num)) {
      return 0;
   }

   replace_page(1, num - 1);
} /* make_page_blank() */

/**
 * @ignore yes
 */
string short(int flags) {
  if (!flags || _ignore_open_page) {
    return ::short(flags);
  }
  if (_open_page) {
    return "open " + ::short(flags);
  }
  return "closed " + ::short(flags);
} /* short() */

/**
 * This is over ridden here to allow the open/closed sttus of the book to be
 * matched.
 * @ignore yes
 */
string *parse_command_adjectiv_id_list() {
   if (_open_page) {
      return ::parse_command_adjectiv_id_list() + ({ "open" });
   }
   return ::parse_command_adjectiv_id_list() + ({ "closed" });
} /* parse_command_adjectiv_id_list() */

/**
 * @ignore yes
 */
string long(string str, int dark) {
  string ret;
  int i;

  if (!_open_page) {
    return ::long(str, dark)+"It is closed.\n";
  }
  ret = ::long(str, dark)+"It is open at page "+_open_page+".\n";
  for (i=_open_page-1;i<sizeof(_pages) && !_pages[i];i++) {
    if (!_pages[i]) {
      ret += "Page "+(i+1)+" has been torn out.\n";
    }
  }
  if (i >= sizeof(_pages)) {
    ret += "All the rest of the pages have been torn out!\n";
  } else {
    if (i != _open_page -1) { /* A page has been torn out... */
      ret += "You can see page "+(i+1)+" however.\n";
    }

    // Only show the page if they "look page of book" or somesuch.
    if(str && strsrch(str, "page") != -1) {
      if (objectp(_pages[i])) {
        ret += (string)_pages[i]->long(str, dark);
      } else {
        ret += _default_page_object->long(str, dark);
      }
    }
  }
  return ret;
} /* long() */

/**
 * Opens the book to the right place.  This is the add_command function.
 * @param indir the indirect objects (not used)
 * @param id_mactch the string matching the id (not used)
 * @param ind_match the string matching the indirect ob (not used)
 * @param args the arguments associated with the pattern
 * @param the pattern which was matched.
 * @see /global/new_parse->add_command()
 * @return 1 if it succeeded, 0 if it failed
 * @ignore yes
 */
protected int do_open(int page) {
  if (!page || page > sizeof(_pages)) {
    add_failed_mess("Could not open to page " + page + ".\n", ({ }));
    return 0;
  }
  if (query_open_page() == page) {
    add_failed_mess("The $D is already open at page " + page + ".\n");
  }
  _ignore_open_page = 1;
  call_out((: _ignore_open_page = 0 :), 4);
  set_open_page(page);
  add_succeeded_mess("$N $V $D to page " + page + ".\n", ({ }));
  return 1;
} /* do_open() */

/**
 * Turns a page of the book.
 * @return always returns 1
 * @ignore yes
 */
protected int do_turn(int number) {
  int tmp;

  tmp = query_open_page();
  if (tmp+number > sizeof(_pages)) {
    set_open_page(0);
    add_succeeded_mess("$N close$s $D.\n");
  } else {
    if (tmp == 0) {
       add_succeeded_mess("$N turn$s $D to page " + number + ".\n");
    }
    set_open_page(tmp + number);
  }
  if (tmp == query_open_page()) {
     add_failed_mess("Unable to turn page of $D.\n", ({ }));
     return 0;
  }
  _ignore_open_page = 1;
  call_out((: _ignore_open_page = 0 :), 4);
  return 1;
} /* do_turn() */

/**
 * Closes the book.
 * @return 0 if it failed, 1 if it succeeded
 * @ignore yes
 */
protected int do_close() {
  if (!query_open_page()) {
    TP->add_failed_mess(TO, "$D is already closed.\n",
                                   ({}));
    return 0;
  }
  _ignore_open_page = 1;
  call_out((: _ignore_open_page = 0 :), 4);
  set_open_page(0);
  return 1;
} /* do_close() */

/**
 * Tears out the current page.
 * @return 0 if it failed, 1 if it succeded
 * @ignore yes
 */
int do_tear(int number) {
  int i;

  if (!_open_page) {
    TP->add_failed_mess(TO, "$D is closed!\n", ({}));
    return 0;
  }

  // do all the pages.
  if(number == 0) {
    _open_page = 1;
    number = sizeof(_pages);
  }

  for(i=0; i<number; i++) {

    if(!tear_current_page_out(TP))
      break;

    if ( _open_page != sizeof( _pages ) ) {
        _open_page++;
    }
  }

  if(i) {
    if(i > 1)
      add_succeeded_mess("$N $V " + i + " pages from $D.\n");
    else
      add_succeeded_mess("$N $V a page from $D.\n");
    return 1;
  }

  return 0;
} /* do_tear() */

/* The stuff redefined for handleing books... */
/**
 * @ignore yes
 */
varargs void set_read_mess(string str, string lang, int size) {
  object ob;

  if (_open_page) {
    ob = query_current_page_clone();
    if (!ob)
      return 0;
    return ob->set_read_mess(str, lang, size);
  }
  return ::set_read_mess(str, lang, size);
} /* set_read_mess() */

/** @ignore yes */
string add_read_mess( string str, string type, string lang, int size ) {
    if( _open_page ) {
        object ob;

        if( ob = query_current_page_clone() )
            return ob->add_read_mess(str, type, lang, size);

        return 0;

    }

    return ::add_read_mess( str, type, lang, size );

} /* add_read_mess() */

/**
 * @ignore yes
 */
mixed query_read_mess() {
  if (_open_page) {
    object ob;

    ob = query_current_page();
    if (!ob) {
      return 0;
    }
    return ob->query_read_mess();
  }
  return ::query_read_mess();
} /* query_read_mess() */

/**
 * @ignore yes
 */
void set_max_size(int siz) {
  object ob;

  if (!_open_page)
    return ::set_max_size(siz);

  ob = query_current_page_clone();
  if (!ob)
    return 0;
  ob->set_max_size(siz);
} /* query_max_size() */

/**
 * @ignore yes
 */
void set_cur_size(int siz) {
  object ob;

  if (!_open_page)
    return ::set_cur_size(siz);

  ob = query_current_page_clone();
  if (!ob)
    return 0;
  ob->set_cur_size(siz);
} /* set_cur_size() */

/**
 * @ignore yes
 */
int query_max_size() {
  object ob;

  if (!_open_page)
    return ::query_max_size();

  ob = query_current_page_clone();
  if (!ob)
    return 0;
  return (int)ob->query_max_size();
} /* query_max_size() */

/**
 * @ignore yes
 */
int query_cur_size() {
  object ob;

  if (!_open_page)
    return ::query_cur_size();

  ob = query_current_page_clone();
  if (!ob)
    return 0;
  return (int)ob->query_cur_size();
} /* query_cur_size() */

/** @ignore yes */
mixed stats() {
  return ({
    ({ "num pages" , sizeof(_pages) }),
    ({ "ignore saved pages" , _ignore_saved_pages }),
    ({ "default page ob" , _default_page_object }),
    ({ "open page", _open_page }),
    ({ "book number" , _book_num }),
  }) + ::stats();
} /* stats() */

/** @ignore yes */
void dest_me() {
  int i;

  for (i=0;i<sizeof(_pages);i++) {
    if (objectp(_pages[i])) {
      _pages[i]->dest_me();
    }
  }
  ::dest_me();
} /* dest_me() */

/** @ignore yes */
mixed query_static_auto_load() {
  if (file_name(TO)[0..8] == "/std/book") {
    return int_query_static_auto_load();
  }
} /* query_static_auto_load() */

/** @ignore yes */
mapping query_dynamic_auto_load() {
  int i;
  mixed ret;
  mapping bing;
  mixed stuff;

  bing = ([
      "::" : ::query_dynamic_auto_load(),
      "default page object" : _default_page_object,
      "open page" : _open_page,
      "book num" : _book_num,
    ]);
  if (!_ignore_saved_pages) {
    ret = ({ });
    for (i=0;i<sizeof(_pages);i++) {
      if (intp(_pages[i])) {
        ret += ({ _pages[i] });
      } else {
        stuff = 0;
        if (TP) {
           catch(stuff = TP->create_auto_load(_pages[i..i]) );
        }
        if (!stuff) {
           catch(stuff = PLAYER_OB->create_auto_load(_pages[i..i]) );
        }
        if (!stuff) {
           catch(stuff = AUTO_LOAD_OB->create_auto_load(_pages[i..i]) );
        }
        ret += ({ stuff });
      }
    }
    bing["pages"] = ret;
  }
  return bing;
} /* query_dynamic_auto_load() */

/** @ignore yes */
void init_dynamic_arg( mapping map ) {
    int i;
    object *tmp, player;

    player = _player;
    if( !player )
        player = TP;

    if( map["::"] )
        ::init_dynamic_arg( map["::"] );

    if( map["default page object"] ) {
        _default_page_object = map["default page object"];
        load_object(_default_page_object);
        _def_p_obj = find_object(_default_page_object);
    }

    if( map["pages"] && !_ignore_saved_pages ) {
        // If setup() created any pages, dest them in favor of the saved pages.
        if( _pages ) {
            for( i = 0; i < sizeof(_pages); i++ ) {
                if( objectp(_pages[i]) )
                    _pages[i]->move("/room/rubbish");
            }
        }

        _pages = ({ });

        for( i = 0; i < sizeof(map["pages"]); i++ ) {
            if( intp(map["pages"][i]) ) {
                _pages += ({ map["pages"][i] });
            } else {
                tmp = (object *)player->load_auto_load_to_array(
                    map["pages"][i], TO, player );
                tmp->add_property("my book", TO );
                tmp->move(TO);
                _pages += tmp;
            }
        }
    }

    _book_num = map["book num"];
    set_open_page( map["open page"] );

} /* init_dynamic_arg() */

/**
 * Sets the object to use as the default page.  If this is not set the
 * the object /std/stationery/paper.c will be used.
 * @param ob the object to use as the default page
 */
void set_default_page_object(string obj) {
  load_object(obj);
  if (find_object(obj)) {
    _default_page_object = obj;
    _def_p_obj = find_object(obj);
  }
} /* set_default_page_object() */

/**
 * This method returns the default page object.
 * @return the default page object (as a string)
 */
string query_default_page_object() {
   return _default_page_object;
} /* query_default_page_object() */

/**
 * This method creates a new default page object for this book.  THis
 * can be used for whatever nefarious purposes you want.
 * @return a new default page object
 */
object create_default_page_object() {
   return clone_object(_default_page_object);
} /* create_default_page_object() */

/**
 * Queries the number of pages in the book.
 * @return the number of pages in the book
 * @see set_no_pages()
 */
int query_num_pages() {
  return sizeof(_pages);
} /* query_num_pages() */

/**
 * This method returns the current number of the book.  This is assigned
 * and used in conjunction with the book handler.
 * @see /handlers/book_handler.c
 * @see /std/print_shop.c
 * @return the current book number
 */
int query_book_num() {
   return _book_num;
} /* query_book_num() */

/**
 * This method sets the current number of the book.  This is assigned
 * and used in conjunction with the book handler.
 * @see /handlers/book_handler.c
 * @see /std/print_shop.c
 * @param num the new book number
 */
void set_book_num(int num) {
   _book_num = num;
} /* set_book_num() */

/**
 * This method returns the current setting of the ignore saved
 * pages variable.  If this is true then
 * the pages form the players auto_load stuff will be ignored totaly
 * and only the page creates in setup would be
 * used.
 * @see set_ignore_saved_pages()
 * @return the current ignore saved page attribute
 */
int query_ignore_saved_pages() {
   return _ignore_saved_pages;
} /* query_ignore_saved_pages() */

/**
 * This method sets the current setting of the ignore saved
 * pages variable.  If this is true then
 * the pages form the players auto_load stuff will be ignored totaly
 * and only the page creates in setup would be
 * used.  This can only be called from an object
 * which inherits this one (hence the protected method).
 * @param saved the new value of the saved attribute
 * @see query_ignore_saved_pages()
 */
protected void set_ignore_saved_pages(int saved) {
   _ignore_saved_pages = saved;
} /* set_ignore_saved_pages() */

/**
 * This method is called by the auto loading process to set the current
 * player on this object.
 * @param player the player to set
 * @see query_player()
 */
void set_player(object player) {
   _player = player;
} /* set_player() */

/**
 * This method will return  the player associated with the auto loading
 * process.
 * @return the player in use by the autoloading
 * @see set_player()
 */
object query_player() {
   return _player;
} /* query_player() */

/**
 * @ignore
 * This will determine the books read short, which is different to a
 * normal short because it says wild stuff about the cover and things.
 */
string query_read_short(object player, int ignore_labels) {
  if(!::query_read_short(player, 0))
    return 0;
  if (!_open_page) {
    return "the cover of " + ::query_read_short(player, 0);
  }

  return "page " + query_num(_open_page) + " of " +
    ::query_read_short(player, 1);
} /* query_read_short() */

/**
 * @ignore
 * This is overridden specifically to stop labels appearing on anything
 * but the cover.
 */
string query_readable_message(object player, int ignore_labels) {
   return ::query_readable_message(player, _open_page != 0);
} /* query_readable_message() */