Import All Things Devours by Toby Ord (half sick of shadows)
authorJason Self <j@jxself.org>
Mon, 19 Aug 2019 01:39:31 +0000 (18:39 -0700)
committerJason Self <j@jxself.org>
Mon, 19 Aug 2019 01:39:31 +0000 (18:39 -0700)
Release 3

From
http://www.amirrorclear.net/flowers/game/devours/devours.inf

.gitignore [new file with mode: 0644]
.gitmodules [new file with mode: 0644]
COPYING [new file with mode: 0644]
README [new file with mode: 0644]
build.sh [new file with mode: 0755]
devours.inf [new file with mode: 0644]
lib [new submodule]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..7ee403d
--- /dev/null
@@ -0,0 +1 @@
+devours.z*
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..dc70f3a
--- /dev/null
@@ -0,0 +1,3 @@
+[submodule "lib"]
+       path = lib
+       url = https://jxself.org/git/informlib.git
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..be3f7b2
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU Affero General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero General Public License from time to time.  Such new versions
+will be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU Affero General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU Affero General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU Affero General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero General Public License
+    along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU AGPL, see
+<https://www.gnu.org/licenses/>.
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..6c18b4f
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+This repository contains a copy of All Things Devours by Toby Ord 
+(half sick of shadows).
+
+The author released the game to the public domain, allowing unlimited 
+permission to copy and change it.
+
+https://ifdb.tads.org/viewgame?id=5e23lnq25gon9tp3
+http://mirror.ifarchive.org/if-archive/games/source/inform/devours.inf
+http://www.amirrorclear.net/flowers/game/devours/devours.inf
+
+The recommended way to get a copy of this git repository is a 
+recursive clone:
+
+       git clone --recursive https://jxself.org/git/?p=devours.git
+
+This will clone all submodules recurively. If you did not perform a 
+recurive clone, once you have a copy of this git repository you will 
+also need the source code for the standard library:
+
+       git submodule update --init --recursive
+
+To compile this game you will also need version 6 of the Inform 
+compiler from https://jxself.org/git/?p=inform.git
+
+Once the compiler has been compiled and is ready for use return to 
+this directory and run:
+
+       inform +include_path=lib devours.inf
+
+Or you can run the included build.sh script which does the same thing.
+
+You will then get the story file for this game that can be run using 
+any appropriate Z-Machine interpreter, such as Frotz. Your GNU/Linux 
+distro probably has that packaged already for easy installation.
+
+--
+Copyright (C) 2019 Jason Self <j@jxself.org>
+
+This file is free software: you may copy, redistribute and/or modify 
+it under the terms of the GNU Affero General Public License as 
+published by the Free Software Foundation, either version 3 of the 
+License, or (at your option) any later version.
+
+This file 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 
+Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public 
+License along with this file. If not, see https://gnu.org/licenses/
\ No newline at end of file
diff --git a/build.sh b/build.sh
new file mode 100755 (executable)
index 0000000..884b14b
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env sh
+#
+# Copyright (C) 2019 Jason Self <j@jxself.org>
+#
+# This file is free software: you may copy, redistribute and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This file 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
+# Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public
+# License along with this file. If not, see https://gnu.org/licenses/
+
+inform +include_path=lib devours.inf
\ No newline at end of file
diff --git a/devours.inf b/devours.inf
new file mode 100644 (file)
index 0000000..e89a039
--- /dev/null
@@ -0,0 +1,5664 @@
+!% +code_path=../../Games/devours
+!% $MAX_STATIC_DATA=150000
+
+
+!============================================================================
+
+! This program was written by Toby Ord (half sick of shadows) and has been
+! released into the public domain, so you are legally free to be distribute 
+! and modify it as you see fit. So long as you do so in good faith and with good
+! taste (or sufficient taste) then you have my blessing.
+!
+! Oh, and apologies for the messy code! It was my first program in Inform.
+
+Constant Story "All Things Devours";
+
+Constant Headline
+   "^Written for IFComp 2004 by half sick of shadows.^
+     This is the post-competition release.^
+     It is in the public domain and may thus be freely copied or modified.^
+     First-time players should type 'about'.^";
+
+
+Release 3;    ! post-competition release, (plus 1 bugfix)
+
+Replace DrawStatusLine;
+Replace ScoreSub;
+
+
+!============================================================================
+! Constants and Globals
+!
+
+Constant DEATH_MENTION_UNDO;
+
+! EARLIEST_TIME is a time before which no action can happen 
+! (can't time travel to before this time)
+! start_time is when the player arrives.
+! From ten seconds earlier,
+! the player is outside (and can interfere with escape attempts at this time)
+! <<< thus the EARLIEST_TIME must be at least ten seconds before start_time >>>
+! FINAL_TIME is when the security team arrive and any attempt to stay beyond this
+! will get you caught.
+
+! the time units are 5 second blocks
+
+Global my_time;        ! used instead of the_time to allow sub-minute turns
+
+! the timeline has the player in a non-specified 'limbo' from EARLIEST_TIME to
+
+Constant EARLIEST_TIME = ((4 * 60) + 13) * 12 + 11;
+Constant FINAL_TIME =    ((4 * 60) + 23) * 12 + 0;
+
+Global start_time =      ((4 * 60) + 17) * 12 + 0;
+Global early_guard_time = EARLIEST_TIME;            ! but this changes in the challenge mode
+
+Constant CHALLENGE_EARLY_GUARD_TIME = ((4 * 60) + 15) * 12 + 11;
+
+
+! the times of the two military experiments, if allowed to happen
+
+Constant EXPERIMENT1_TIME = (( 9 * 60) + 27) * 12 + 3;
+Constant EXPERIMENT2_TIME = ((11 * 60) + 33) * 12 + 9;
+
+Constant GAME_LENGTH = FINAL_TIME - EARLIEST_TIME;
+
+Constant LATER_ = -1;  ! A constant to represent a later time
+
+Constant DEFAULT_SIREN_TIMEOUT   = 16;      ! the time before the guard arrives 
+Constant CHALLENGE_SIREN_TIMEOUT = 11;      ! 1:20 vs. 0:55
+
+Constant TIME_BEFORE_DRAGGED_OFF = 4;   ! the time between arrest and removal
+
+Constant MAX_TIME_TRAVELS = 2;
+
+! ***************** Important ********************
+! This MUST be set to be equal to 2 to the power of MAX_TIME_TRAVELS
+
+Constant MAX_ITEM_COPIES = 4;
+
+! Constants for death states
+
+Constant ACCELERATED_          =  4;   ! brought about the premature destruction of Boston
+Constant USELESS_              =  5;   ! achieved nothing of consequence
+Constant DELAYED_              =  6;   ! delayed the destruction by blowing up prototype
+Constant SAVED_DEAD_           =  7;   ! saved the city but died
+Constant SAVED_CAUGHT_         =  8;   ! saved the city but caught
+Constant SAVED_FREE_           =  9;   ! saved the city and free
+Constant SAVED_FREE_CHALLENGE_ = 10;   ! saved the city and free and completed the challenge
+! Constants for object states
+
+Constant NA_      = -2;
+Constant UNKNOWN_ = -1;
+Constant LOCKED_  =  0;
+Constant CLOSED_  =  1;
+Constant OPEN_    =  2;
+
+! Potentially dangerous actions:
+
+Constant NONE_                      =  0;
+Constant LOCK_                      =  1;
+!Constant OPEN_                     =  2;    Not needed since defined above
+Constant UNLOCK_                    =  3;
+Constant X_CCTV_                    =  4;
+Constant X_UPSTAIRS_CORRIDOR_       =  5;
+Constant X_UPSTAIRS_LANDING_        =  6;
+Constant X_GROUND_CORRIDOR_         =  7;
+Constant X_FOYER_                   =  8;
+Constant X_BASEMENT_CORRIDOR_       =  9;
+Constant X_BASEMENT_LANDING_        = 10;
+Constant X_BALCONY_                 = 11;
+Constant TAKE_FLASHLIGHT_           = 12;
+Constant BLOW_BASEMENT_LIGHT_       = 13;
+Constant SING_                      = 14;     ! these are not dangerous in the same way
+Constant SHOUT_                     = 15;     ! but need to be caught and replayed
+
+Global time_travelled;
+Global last_travel_time;
+
+Global d_paradox;
+Global d_caught;
+Global d_detained;
+Global d_escaped;
+Global d_exploded;
+Global d_killed_by_bomb;
+Global d_injured_by_bomb;
+Global d_fs_hears_bomb;
+Global d_fs_killed_by_bomb;
+Global d_destroyed_notes;
+Global d_destroyed_prototype;
+
+      !! The moveable items (which can be taken back in time):
+
+Array bomb          --> MAX_ITEM_COPIES;
+Array id_card       --> MAX_ITEM_COPIES;
+Array equipment_key --> MAX_ITEM_COPIES;
+Array deutsch_key   --> MAX_ITEM_COPIES;
+Array flashlight    --> MAX_ITEM_COPIES;
+Array battery       --> MAX_ITEM_COPIES;
+Array cable         --> MAX_ITEM_COPIES;
+Array crowbar       --> MAX_ITEM_COPIES;
+Array notes         --> MAX_ITEM_COPIES;
+
+Array former_self   --> MAX_TIME_TRAVELS;
+
+
+       !! The locations of various things at various times
+       !! These contain an immense amount of info:
+       !!     Location of each copy of that item at each time for each run through
+       !! Amongst other things, this allows one to recreate the world at a given time
+
+Array player_loc        --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+
+Array bomb_loc          --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array id_card_loc       --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array equipment_key_loc --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array deutsch_key_loc   --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array flashlight_loc    --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array battery_loc       --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array cable_loc         --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array crowbar_loc       --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array notes_loc         --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+
+       !! The states of various things at various times
+
+Global prototype_fixed_time = UNKNOWN_;
+Global siren_start_time     = UNKNOWN_;
+
+Array flashlight_state  --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+Array bomb_setting      --> (GAME_LENGTH + 1) *
+                            (MAX_ITEM_COPIES) * (MAX_TIME_TRAVELS + 1);
+
+!! activity_target is used to distinguish which door was (dangerously) locked/unlocked/opened
+
+Array dangerous_activity            --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array activity_target               --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+
+Array siren_state                   --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array panel_setting                 --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array ground_equipment_light        --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array basement_equipment_light      --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+
+Array main_doors_state              --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array basement_door_state           --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array ground_door_state             --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array upstairs_door_state           --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array balcony_door_state            --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array conference_window_state       --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array deutsch_door_state            --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array basement_equipment_door_state --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array ground_equipment_door_state   --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+
+Array main_doors_smashed            --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array basement_door_smashed         --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array ground_door_smashed           --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array upstairs_door_smashed         --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+Array balcony_door_smashed          --> (GAME_LENGTH + 1) * (MAX_TIME_TRAVELS + 1);
+
+
+Global poem_interleaving        = false;
+Global initialising             = true;
+Global first_turn               = true;
+Global challenge                = false;
+Global siren_timeout            = DEFAULT_SIREN_TIMEOUT;
+Global instant_action_this_turn = false;
+Global warned_of_jump           = false;
+Global id_card_used             = false;
+Global have_looked_at_bench     = false;
+Global prototype_seen           = false;
+
+!============================================================================
+
+
+
+Include "Parser";
+
+Object LibraryMessages
+with before [;
+    Jump:
+        if (real_location == balcony) {
+            Jumped();
+            return true;
+        }
+        "You jump on the spot, fruitlessly.";
+    Listen:
+        if ((siren_start_time ~= UNKNOWN_) && (siren_start_time < my_time))
+            return true;
+        else if (Get2D(dangerous_activity, time_travelled-1, my_time-EARLIEST_TIME) == SHOUT_)
+           return true;
+        else if (Get2D(dangerous_activity, time_travelled-1, my_time-EARLIEST_TIME) == SING_)
+           return true;
+        else
+           "You can hear nothing but a soft electric hum.";
+    Burn:
+        "You have no source of flame.";
+    Sing:
+        "You sing out a few clear notes.";
+    Miscellany:
+        if (lm_n == 44)
+            "It is not clear what you are trying to refer to with 'all'.";
+]; 
+
+Include "VerbLib";
+
+
+!============================================================================
+
+
+! Object classes
+
+Class   Room
+  with  before [t;
+          Inv, Look:
+            if (initialising) {
+                initialising = false;
+                return false;
+            }
+            instant_action_this_turn = true;
+            return false;
+          Sing:
+            for (t=0 : t<time_travelled : t++) {
+                if ((former_self-->t notin limbo) && 
+                    ((siren_start_time == UNKNOWN_) || (siren_start_time > my_time))) {
+                    
+                    print "You sing out a few clear notes.^";
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                    print (Nearby) 0, "your former self hears the muffled sounds of your
+                           singing.^^Something of an anticlimactic way to kill 
+                           so many millions of people...^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                    return true;
+                }
+            }
+            Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,SING_);
+            return false;
+        ],
+        each_turn [t i;  
+            first_turn = false;
+            if (instant_action_this_turn) {
+                instant_action_this_turn = false;
+                return true;
+            }
+            MoveFloatingObjects();
+            my_time++;
+            if (time_travelled > 0) {
+                for(i=0 : i < Exp(2,time_travelled-1) : i++) {
+                    MoveObject(bomb, bomb_loc, i);
+                    MoveObject(id_card, id_card_loc, i);
+                    MoveObject(equipment_key, equipment_key_loc, i);
+                    MoveObject(deutsch_key, deutsch_key_loc, i);
+                    MoveObject(flashlight, flashlight_loc, i);
+                    MoveObject(battery, battery_loc, i);
+                    MoveObject(cable, cable_loc, i);
+                    MoveObject(crowbar, crowbar_loc, i);
+                    MoveObject(notes, notes_loc, i);
+                }
+                
+                if (my_time == prototype_fixed_time)
+                    prototype.fixed = true;
+                                      
+                MaybeSetBombs();
+                MaybeSetFlashlights();
+                MaybeSetPanel(panel_setting);
+                MaybeSetBasementLight(basement_equipment_light);
+                MaybeSetGroundLight(ground_equipment_light);
+                MaybeSetAutomaticDoor(main_doors, main_doors_state);
+                MaybeSetAutomaticDoor(basement_door, basement_door_state);
+                MaybeSetAutomaticDoor(ground_door, ground_door_state);
+                MaybeSetAutomaticDoor(upstairs_door, upstairs_door_state);
+
+                MaybeBreakDoor(main_doors, main_doors_smashed);
+                MaybeBreakDoor(basement_door, basement_door_smashed);
+                MaybeBreakDoor(ground_door, ground_door_smashed);
+                MaybeBreakDoor(upstairs_door, upstairs_door_smashed);
+                MaybeBreakDoor(balcony_door, balcony_door_smashed);
+                
+                MaybeSing();
+                MaybeShout();
+
+!-- from here down paradox may occur and we need to be able to stop if one occurs  if (~~d_paradox)...
+                
+                for(t=0 : t < time_travelled : t++)
+                    MoveFormerSelf(t);
+
+                MaybeSetManualDoor(balcony_door, balcony_door_state);
+                MaybeSetManualDoor(conference_window, conference_window_state);
+                MaybeSetManualDoor(deutsch_door, deutsch_door_state);
+                MaybeSetManualDoor(basement_equipment_door, basement_equipment_door_state);
+                MaybeSetManualDoor(ground_equipment_door, ground_equipment_door_state);
+                                
+            }
+
+            MaybeCloseAutomaticDoor(main_doors);
+            MaybeCloseAutomaticDoor(basement_door);
+            MaybeCloseAutomaticDoor(ground_door);
+            MaybeCloseAutomaticDoor(upstairs_door);
+                            
+            ObserveLocations();
+            ObserveBombs();
+            ObserveFlashlights();
+            ObserveSiren();
+            ObservePanel();
+            ObserveBasementLight(basement_equipment_light);
+            ObserveGroundLight(ground_equipment_light);
+            ObserveAutomaticDoor(main_doors, main_doors_state);
+            ObserveAutomaticDoor(basement_door, basement_door_state);
+            ObserveAutomaticDoor(ground_door, ground_door_state);
+            ObserveAutomaticDoor(upstairs_door, upstairs_door_state);
+            ObserveManualDoor(balcony_door, balcony_door_state);
+            ObserveManualDoor(conference_window, conference_window_state);
+            ObserveManualDoor(deutsch_door, deutsch_door_state);
+            ObserveManualDoor(basement_equipment_door, basement_equipment_door_state);
+            ObserveManualDoor(ground_equipment_door, ground_equipment_door_state);
+
+            ObserveBrokenDoor(main_doors, main_doors_smashed);
+            ObserveBrokenDoor(basement_door, basement_door_smashed);
+            ObserveBrokenDoor(ground_door, ground_door_smashed);
+            ObserveBrokenDoor(upstairs_door, upstairs_door_smashed);
+            ObserveBrokenDoor(balcony_door, balcony_door_smashed);
+   
+            CheckPassiveParadox();
+            CheckActiveParadox();
+       
+            if (~~(Stopped())) {
+                if (siren_start_time ~= UNKNOWN_) {
+                    if (my_time - siren_start_time == 1)
+                            print "^A piercing siren rings out.^";
+                    if (my_time - siren_start_time > 1) {
+                        if (my_time - siren_start_time <= siren_timeout)
+                            print "^The siren wails.^";
+                        else
+                            CaughtInside();
+                    }
+                }
+                if ((my_time > FINAL_TIME) && (~~Stopped()))
+                    CaughtInside();
+            }
+    
+            if (main_doors.just_closed) main_doors.closing_message();
+            if (basement_door.just_closed) basement_door.closing_message();
+            if (ground_door.just_closed) ground_door.closing_message();
+            if (upstairs_door.just_closed) upstairs_door.closing_message();
+
+            MaybeExplodeBombs();
+            
+        ],
+        
+  has   light;
+
+Class   Sight
+  with  before [;
+            Examine: return false;
+            Listen: return false;
+            default:
+                print_ret "You cannot do that from here.";
+        ],
+  has   scenery concealed static;
+Class   PluralSight
+  with  before [;
+            Examine: return false;
+            default:
+                print_ret "You cannot do that to all of ", (the) self, " at once.";
+        ],
+  has   scenery concealed static;
+      
+Class   Prop
+  with  before [;
+            Examine: return false;
+            default:
+                print_ret "You don't need to worry about ", (the) self, ".";
+        ],
+  has   scenery concealed static;
+
+
+Class   Furniture
+  with  before [;
+            Take,Pull,Push,PushDir:
+                print_ret (The) self, " is too heavy for that.";
+        ],
+  has   static supporter;
+
+
+Class   AutomaticDoor
+  with  before [;
+            Take,Pull,Push,PushDir:
+                print_ret (The) self, " is locked in place.";
+            Lock:
+            Close:
+              "Like most automatic doors, this one closes of its own accord.";
+            Attack:
+              if (AmHolding(crowbar)) {
+                  print "You swing the crowbar firmly into the door. It shudders,
+                         a star of cracks reaching out from the point of impact,
+                         but the glass stays in place.^";
+                  self.smashed = true;
+                  StartSiren();
+                  return true;
+              }
+              else
+                "You don't have anything heavy enough to smash the door with.";              
+            Search:
+              <<Examine self>>;             
+        ],
+        just_closed false,
+        smashed false,
+        to_close_at UNKNOWN_,
+        open_self [t;
+            if (self hasnt open) {
+                give self open ~locked;
+                if (self in LocationOf(player))
+                    print "The door slides open with a soft rattle.^";
+            }
+            self.to_close_at = t;
+        ],
+        close_self [;
+            give self ~open locked;
+            self.to_close_at = UNKNOWN_;
+            self.just_closed = true;
+        ],
+        closing_message [;
+            if ((~~Stopped()) && (self in LocationOf(player)))
+                "The automatic door softly slides closed.";
+        ],
+  has   static door openable locked;
+
+Class   ManualDoor
+  with  name 'door' 'to' 'the',
+        before [;
+          Take,PushDir:
+                print_ret (The) self, " is locked in place.";
+          Attack:
+              if (AmHolding(crowbar)) {
+                  print "You swing the crowbar firmly into the door, 
+                         but it barely leaves a mark.^";
+                  return true;
+              }
+              else
+                "You don't have anything heavy enough to break the door with.";              
+          ],  
+        react_before [;
+          Go: if (noun.door_dir() == self.door_dir())
+                  return self.open_by_myself();
+              if (noun.door_dir() == out_to)      !! XX hack, going 'out' always uses door in this game
+                  return self.open_by_myself();
+          Enter: 
+               if (noun == self) return self.open_by_myself(); 
+        ], 
+        open_by_myself [ ks;
+            if (self has open)
+                rfalse;
+            print "(first opening ", (the) self, ")^";
+            ks = keep_silent;
+            keep_silent = true;
+            <Open self>;
+            keep_silent = ks;
+            if (self hasnt open)
+                rtrue;
+            else {
+                IncTime();
+                if (Stopped()) return true;
+            }
+        ], 
+  has   static door openable lockable;
+
+
+[LockUnlockParadox;
+    d_paradox = true;
+    deadflag = 3;
+    Seperator();
+    print "On the other side of the door, your former self hears you turn the
+           key in the lock.^"; 
+    print "^Time unravels...^";
+    Devours(my_time);                            
+];
+
+[OpenParadox;
+    d_paradox = true;
+    deadflag = 3;
+    Seperator();
+    print "On the other side, your former self sees the door open in front
+           of her.^"; 
+    print "^Time unravels...^";
+    Devours(my_time);                            
+];
+
+[CloseParadox;
+    d_paradox = true;
+    deadflag = 3;
+    Seperator();
+    print "On the other side, your former self sees the door close in front
+           of her.^"; 
+    print "^Time unravels...^";
+    Devours(my_time);                            
+];
+
+[OpenManualDoor door ks;
+    if (door has locked) {
+        if (door.with_key_type == nothing
+          || ~~AmHolding(door.with_key_type)) 
+              "Try as you might, none of your keys will unlock the door."; 
+        print "(first unlocking ", (the) door, ")^"; 
+        ks = keep_silent; 
+        keep_silent = true; 
+        <Unlock door (GetHeld(door.with_key_type))>; 
+        keep_silent = ks; 
+        if (door has locked) 
+            return true;
+        else {
+            IncTime();
+            if (Stopped()) return true;
+        }
+    }
+    Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,OPEN_);
+    Put2D(activity_target,time_travelled,my_time-EARLIEST_TIME,door);
+    return false;
+];
+
+[UnlockManualDoor door key;
+    Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,UNLOCK_);
+    Put2D(activity_target,time_travelled,my_time-EARLIEST_TIME,door);
+    if (door has locked) {
+      if ( IsOfType(key,door.with_key_type) ) {
+          give door ~locked;
+          if (~~keep_silent)
+              print (The) key, " turns smoothly in the lock.^";
+          return true;
+      }
+      else
+          "It does not fit in the lock.";
+    }
+    return false;
+];
+
+[LockManualDoor door key ks;
+    if (door has open) {
+        print "(first closing ", (the) door, ")^"; 
+        ks = keep_silent;
+        keep_silent = true;
+        <Close door>;
+        keep_silent = ks; 
+        if (door has open) 
+            rtrue; 
+        IncTime();
+        if (Stopped()) return true;
+    }
+    Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,LOCK_);
+    Put2D(activity_target,time_travelled,my_time-EARLIEST_TIME,door);
+    if (door hasnt locked) {
+        if ( IsOfType(key,door.with_key_type) ) {
+            give door locked;
+          if (~~keep_silent)
+              print (The) key, " turns smoothly in the lock.^";
+          return true;
+        }
+        else
+            "It does not fit in the lock.";
+    }
+    return false;
+];
+
+
+Class   FakeDoor
+  with  name 'door' 'to' 'the',
+        before [;
+          Take,PushDir:
+                print_ret (The) self, " is locked in place.";
+          Unlock:
+              if (IsOfType(second,crowbar))
+                  <<Attack self>>;
+          Attack:
+            if (AmHolding(crowbar)) {
+                print "You swing the crowbar firmly into the door, 
+                       but it barely leaves a mark.^";
+                return true;
+            }
+            else
+              "You don't have anything heavy enough to break the door with.";              
+          Enter:
+            "The door is locked.";
+        ],
+        door_to nothing,
+        door_dir nothing,
+        with_key_type nothing,
+  has   static door openable lockable locked;
+
+
+!============================================================================
+
+! the moveable objects (defined as classes)
+! with trailing _ to avoid ambiguity with individual item names
+
+
+Class   Bomb_(MAX_ITEM_COPIES) 
+  with  short_name "timed explosive device",
+        plural "timed explosive devices",
+        description [t i;
+            print "A length of steel pipe filled with powder and fused with a digital timer.
+                   Not your most elegant piece of work, but it will
+                   hopefully do the job.^";
+            t = (self.time_value - my_time) * 5 + self.left_over_seconds;
+            if (self.time_value == NA_) 
+                print "^You have not yet set the timer.^";
+            else {
+                if (t == -4)
+                    print "^On the timer's small LED screen, the number 0 
+                           blinks out at you.^";
+                else {
+                    print "^On the timer's small LED screen, the numbers ";
+                    for (i = t+4 : (i>t) && (i>0) : i--)
+                        print i, ", ";
+                    if (t < 0)
+                        print 0;
+                    else
+                        print t;
+                    print "... blink out at you insistently, illuminating
+                           the room with faint blue-green flashes.^";
+                }
+            }
+            ],
+        name 'time' 'timed' 'explosive' 'device' 'bomb' 'timebomb' 'C4'
+             'timer' 'digital' 'pipe'
+             'devices//p' 'bombs//p' 'timebombs//p' 'timers//p',
+        time_value NA_,
+        left_over_seconds 0,
+        before [;
+          Set:
+            print "To set the explosive device,
+                       you need to specify a number of seconds,
+                       for example, with 'set timer to 30'.^";
+            return true;
+          SetTo:
+            if (self.time_value ~= NA_) {
+                print "(first resetting the timer)^";
+                self.time_value = NA_;
+            }
+            if (second > 0 && second <= 100) {
+                self.time_value = my_time + (second/5);
+                self.left_over_seconds = second%5;
+                print "Time until detonation: ", (self.time_value - my_time) * 5
+                                                                 + self.left_over_seconds;
+                print " seconds.^";
+                if (parent(self) == player)
+                    print "(you probably don't want to be carrying the device
+                            when that occurs...)^";
+            }
+            else {
+                print "Your timer only accepts between 1 and
+                       100 seconds.^";
+            }
+            return true;
+          Reset:
+             if (self.time_value ~= NA_) {
+                 self.time_value = NA_;
+                 "You reset the timer.";
+             }
+             else
+                "The timer is not currently set.";
+          ],
+  has  ;
+
+Class   IDCard_(MAX_ITEM_COPIES) 
+  with  short_name "ID card",
+        plural "ID cards",
+        description "Natalie Williams.^
+                     Deutsch Lab.^
+                     Doctoral Student, MIT^
+                     ^
+                     On the right is a familiar photo of you, back when you
+                     wore your hair long. 
+                     A black magnetic stripe runs the width of the reverse.",
+        name 'id' 'card' 'cards',
+        before[; Insert:
+            if (second == id_slot){
+                    if (second in foyer or upstairs_landing) {
+                        "The slot emits a small beep and your card is rejected.";
+                    }
+                    if (second in basement_landing) {
+                        if (~~id_card_used) {
+                            print "You swipe your card through the slot, and hold your breath.^";
+                            basement_door.open_self(my_time+1);
+                            print "Perfect. Just as you'd hoped.
+                                   The bastards hadn't even thought to disable your card.^";
+                            id_card_used = true;
+                        }
+                        else
+                            basement_door.open_self(my_time+1);
+                        return true;
+                    }
+            }
+            if (second == ground_door or upstairs_door 
+                && player in foyer or upstairs_landing) {
+                    "The slot emits a small beep and your card is rejected.";
+            }
+            if ((second == basement_door) && (player in basement_landing)) {
+                basement_door.open_self(my_time+1);
+                return true;
+            }
+       ],
+  has  ;
+
+Class   Crowbar_(MAX_ITEM_COPIES) 
+  with  short_name "crowbar",
+        plural "crowbars",
+        name 'crow' 'bar' 'crowbar' 'black' 'crowbars//p' 'bars//p',
+        description "A curved black crowbar.",
+  has;
+
+Class   Flashlight_(MAX_ITEM_COPIES) 
+  with  short_name "flashlight",
+        plural "flashlights",
+        name 'flashlight' 'torch' 'flashlights//p' 'torches//p'
+             'flash' 'metallic' 'blue' 'metallic-blue',
+        description "A small metallic-blue flashlight.",
+        capacity 2,
+        before [;
+          SwitchOn:
+            if (self has on)
+                "That's already on.";
+            if (BatteriesContained(self) == 2) {
+                give self on;
+                if (real_location == basement_equipment ||
+                    (real_location == ground_equipment && ground_equipment.lit == false)) {
+                    <Look>;
+                    instant_action_this_turn = false;
+                    return true;
+                }
+                else
+                  "A thin beam of icy light shines forth.";
+            }
+            if (BatteriesContained(self) == 1) {
+                "The switch clicks, but no light is forthcoming.
+                 It looks as if you will need two batteries.";
+            }
+            if (BatteriesContained(self) == 0) {
+                "The switch clicks, but no light is forthcoming.
+                 Not surprising considering flashlights usually need batteries.";
+            }
+          SwitchOff:
+            if (player in basement_equipment)
+                MoveMoveableChildren(basement_equipment,basement_equipment_gloom);
+            else if ((player in ground_equipment) && (ground_light_switch hasnt on))
+                MoveMoveableChildren(ground_equipment,ground_equipment_gloom);
+          Receive:
+            if (~~IsOfType(noun,battery))
+                print_ret (The) noun, " won't fit in the flashlight.";
+          Take:
+            Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,TAKE_FLASHLIGHT_);
+            return false;
+        ],
+        after [;
+          LetGo:
+            if (self has on) {
+                print "As you remove the battery, the light fails.^";
+                give self ~on;
+                if (player in basement_equipment)
+                    MoveMoveableChildren(basement_equipment,basement_equipment_gloom);
+                else if ((player in ground_equipment) && (ground_light_switch hasnt on))
+                    MoveMoveableChildren(ground_equipment,ground_equipment_gloom);
+                return false;
+            }
+        ],
+  has container open switchable;
+
+Class   Battery_(MAX_ITEM_COPIES) 
+  with  short_name "battery",
+        plural "batteries",
+        name 'battery' 'batteries//p' 'AA',
+        description "An AA sized battery.",
+        before [;
+          Remove:
+            <<Take noun>>;
+        ],
+  has;
+
+Class   Cable_(MAX_ITEM_COPIES) 
+  with  short_name "length of ribbon cable",
+        plural "lengths of ribbon cable",
+        name 'cable' 'wire' 'cables//p' 'wires//p' 'ribbon' 'length' 'lengths//p' 'of',
+        description "A 10cm length of ribbon cable. It will do nicely.",
+        before[;
+          Tie:
+            if (second == control_panel or prototype)
+                <<Tie prototype>>;
+            if (second == nothing)
+                if (real_location == deutsch_lab or prototype_interior)
+                    <<Tie prototype>>;
+                else
+                    "There is nothing here that you could attach the cable to.";
+            else
+                "You cannot attach the cable to that.";
+        ],
+  has;
+
+Class   Notes_(MAX_ITEM_COPIES) 
+  with  short_name "collection of notes",
+        plural "collections of notes",
+        name 'collection' 'notes' 'collections//p',
+        description "Your research notes. The hundred or so pages here comprise
+                     everything you have written so far. It would not be easy for
+                     someone else to turn the scribbles herein into another working
+                     prototype, but it may just be possible.",
+        before[;
+          Eat:
+            "You look determinedly at the thick bundle of papers, but there is no
+             way that you could eat more than a couple of pages. You had better think
+             of something a little more sensible.";
+          Attack, Cut:
+            "There are about a hundred pages and there is no way that you could tear them
+             up in time.";
+        ],
+  has;
+
+Class   EquipmentKey_(MAX_ITEM_COPIES) 
+  with  short_name "worn brass key",
+        plural "worn brass keys",
+        name 'key' 'equipment' 'brass' 'worn' 'keys//p',
+        description "A well worn brass key. It opens the various
+                 equipment rooms in the complex.",
+  has;
+
+Class   DeutschKey_(MAX_ITEM_COPIES) 
+  with  short_name "bright steel key",
+        plural "bright steel keys",
+        name 'key' 'deutsch' 'steel' 'bright' 'keys//p',
+        description "A bright steel key. It unlocks the door to the Deutsch lab, downstairs.",
+  has;
+
+Class   FormerSelf_(MAX_ITEM_COPIES)
+  with  short_name "your former self",
+        plural "your former selves",
+        name 'self' 'former' 'past' 'selves//p',
+        description "She looks strangely familiar.",
+  has animate proper container concealed;
+
+
+!===============================================================================
+! The one-of-a-kind moveable objects
+
+Object myselfobj "(self object)"
+  with 
+    short_name "yourself",
+    description "Dark hair frames a warm face. Despite the anxiety written now in your
+                 tense brow, the confidence of youth and vibrancy of intellect are clear.
+                 There is a depth in your clear green eyes.",
+    capacity 100,
+    number 0,
+    orders 0,
+    weakness 0,
+  has concealed animate proper transparent;
+
+
+Object skeleton_key "skeleton key (fake item to neaten code)"
+  with
+    name 'key' 'skeleton',
+    description "A skeleton key. And I thought they were make-believe!",
+  has;
+
+
+!===============================================================================
+! The rooms
+
+!-----------------------------------------------
+! Generic props and sights:
+
+Prop   walls "walls"
+  with name 'wall' 'walls',
+       found_in [;
+           if (location ~= prototype_interior)
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Prop   floor "floor"
+  with name 'floor' 'ground' 'carpet',
+       description "The floor is covered by a thin carpet in a dark but warm gray.",
+       found_in [;
+           if ((location ~= balcony) && (location ~= prototype_interior))
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Prop   ceiling "ceiling"
+  with name 'ceiling',
+       found_in [;
+           if (location ~= prototype_interior)
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Sight   darkness "darkness"
+  with name 'darkness' 'dark' 'gloom',
+       description "You cannot see what lies in the darkness.",
+       before [;
+          Examine:
+          Listen:
+              return false;
+          default:
+              "It is not clear what you mean.";
+       ],
+       found_in [;
+           return true;
+       ],
+  has  ;
+
+Sight   shadows "shadows"
+  with name 'shadows' 'shadow' 'corners' 'cobwebs',
+       description "Shadows fill the corners of the rooms like old cobwebs.",
+       before [;
+          Examine:
+          Listen:
+              return false;
+          default:
+              "It is not clear what you mean.";
+       ],
+       found_in [;
+           return true;
+       ],
+  has  ;
+
+Sight   complex "complex"
+  with name 'complex' 'building' 'surface' 'surfaces' 'texture' 'textures',
+       description "The building has modern but ultimately shallow feel.
+                    There is a preoccupation with surfaces and textures.
+                    Almost everything is coloured with dark, yet somewhat warm, shades of gray,
+                    darkened further by the midnight gloom.",
+       before [;
+          Examine:
+          Listen:
+              return false;
+          default:
+              "It is not clear what you mean.";
+       ],
+       found_in [;
+           return true;
+       ],
+  has  ;
+
+Prop   lights "lights"
+  with name 'lights' 'light' 'fluorescent',
+       description "Most of the overhead lights are currently off, leaving the complex in dim half-light.",
+       before [;
+           SwitchOn:
+             "Switching on the overhead lights would alert security to your presence, and besides, you
+              can see clearly enough in the gloom.";
+       ],
+       found_in [;
+           if ((location ~= balcony) && (location ~= prototype_interior) && 
+               (location ~= basement_equipment) && (location ~= ground_equipment))
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Prop   stairs "stairs"
+  with name 'stairs' 'staircase',
+       before [;
+         Climb:
+             if (self in foyer or basement_landing)
+                 <<Go u_obj>>;
+             if (self in upstairs_landing)
+                 "You are already at the top of the stairs.";
+       ],
+       found_in basement_landing foyer upstairs_landing,
+  has  ;
+  
+!-----------------------------------------------
+! Item-related props and sights:
+
+Prop   beam "flashlight beam"
+  with name 'beam' 'blue-white' 'blue' 'white',
+       description "A thin icy beam that cuts through the darkness.",
+       found_in [;
+           if (Flashlit())
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Prop   photo "photograph"
+  with name 'photo' 'photograph' 'long' 'hair',
+       description "You look young, bright and proud of
+                    your new position at the lab.",
+       found_in [;
+           if (AmHolding(id_card) || IsIn(id_card,real_location))
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+Prop   stripe "magnetic stripe"
+  with name 'stripe' 'magnetic' 'reverse' 'back',
+       description "It is the type of magnetic stripe found on the back of a regular credit card,
+                    but is used to open the automatic doors in the building.",
+       found_in [;
+           if (AmHolding(id_card) || IsIn(id_card,real_location))
+               return true;
+           else
+               return false;
+       ],
+  has  ;
+
+!-----------------------------------------------
+
+Room  foyer "Foyer"
+  with  name 'foyer',
+        description
+            "A darkened foyer, presided over by a security desk near the north wall.
+             Floating above it in the capacious darkness is
+             a small landing. A set of stairs both rises up to meet it 
+             and stretches downwards into the dark.",
+        u_to upstairs_landing,
+        d_to basement_landing,
+        n_to ground_door,
+        s_to main_doors,
+        cant_go "The only exits are the automatic doors to the north and south,
+                 and the staircases up and down.",
+        lower_name "the foyer",
+  has   ;
+
+Furniture  security_desk "security desk" foyer
+  with  description "A large black desk equipped with four CCTV screens showing
+                     live feeds from around the complex. ",
+        before [;
+          Examine:
+            print "A large black desk equipped with four CCTV screens showing
+                   live feeds from around the complex. ";
+            cctv_screens.display();
+            print "There are also four buttons, labeled 'basement',
+                   'first', 'second' and 'alarm'.^";
+            return true;
+        ],
+        name 'desk' 'security' 'black' 'table',
+  has   scenery;
+
+Object cctv_screens "CCTV images" foyer
+  with description [;
+           print "These screens flash images from the corridors and grounds
+                  of the complex. ";
+           self.display();
+           print "^";
+       ],
+       name 'images' 'CCTV' 'screen' 'screens' 'feed' 'feeds' 'image',
+       display [;
+            Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_CCTV_);
+        
+            if ((my_time == start_time - 1) || (my_time == start_time - 2))
+                print "On one of the screens you see your former self approaching the
+                       complex. ";
+            if (IsIn(former_self,ground_corridor))
+                print "On one of the screens you see your former self in the first
+                       floor corridor. ";
+            if (IsIn(former_self,upstairs_corridor))
+                print "On one of the screens you see your former self in the second
+                       floor corridor. ";
+            if (IsIn(former_self,basement_corridor))
+                print "On one of the screens you see your former self in the basement
+                        corridor. ";
+       ],
+  has  scenery concealed;
+
+
+Object  alarm_button "alarm button" foyer
+  with  description "A discrete black button carefully labeled 'alarm'.",
+        name 'alarm' '^alarm^' 'button' 'black' 'labeled' 'marked',
+        before [; 
+          Push:
+            StartSiren();
+            return true;
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+  has   scenery concealed;
+
+Object  first_button "'first' button" foyer
+  with  description "A small black button carefully labeled 'first'.",
+        name 'first' '^first^' 'floor' 'button' 'black' 'labeled' 'marked',
+        before [; Push:
+            ground_door.open_self(my_time+1);
+            ground_door.known_exterior_opening = true;
+            return true;
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+  has   scenery concealed;
+
+Object  basement_button "'basement' button" foyer
+  with  description "A small black button carefully labeled 'basement'.",
+        name 'basement' '^basement^' 'floor' 'button' 'black' 'labeled' 'marked',
+        before [; Push:
+            basement_door.open_self(my_time+1);
+            "Nothing obvious happens.";
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+  has   scenery concealed;
+
+Object  second_button "'second' button" foyer
+  with  description "A small black button carefully labeled 'second'.",
+        name 'second' '^second^' 'floor' 'button' 'black' 'labeled' 'marked',
+        before [; Push:
+            upstairs_door.open_self(my_time+1);
+            "Nothing obvious happens.";
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+  has   scenery concealed;
+  
+Sight  upstairs_landing_from_foyer "upstairs landing" foyer
+  with description "The landing above is lost in shadow.",
+       name 'upstairs' 'landing',
+  has  ;
+
+Sight  outside_from_foyer "outside" foyer
+  with description "The grounds are empty and still on this frosty night.",
+       name 'grounds' 'outside' 'night',
+  has  ;
+  
+Sight  ground_corridor_from_foyer "corridor" foyer
+  with description [;<<Examine ground_door>>;],
+       name 'corridor',
+  has  ;
+  
+!-----------------------------------------------
+
+Room  basement_landing "Basement Landing"
+  with  name 'landing',
+        description
+            "A cramped space at the bottom of the stairs.
+             A corridor can be seen to the north through the automatic door,
+             and the stairs lead back up to the foyer.",
+        u_to foyer,
+        n_to basement_door,
+        cant_go "The only exits are north and up.",
+        lower_name "the basement landing",
+  has  ;
+
+Sight  foyer_from_basement_landing "foyer" basement_landing
+  with description "You cannot see the foyer properly from here.",
+       name 'foyer' 'upstairs',
+  has  ;
+
+!-----------------------------------------------
+
+Room  upstairs_landing "Upstairs Landing"
+  with  name 'landing',
+        description
+            "A small landing, hanging in the still darkness above the foyer.",
+        d_to foyer,
+        n_to upstairs_door,
+        cant_go "The only exits are north and down.",
+        lower_name "the upstairs landing",
+  has   ;
+
+Sight  foyer_from_upstairs_landing "Foyer" upstairs_landing
+  with description [;
+       Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_FOYER_);
+           if (IsIn(former_self,foyer)) {
+               "From the shadowy landing, you can just make out your former
+                self alone in the foyer.";
+           }
+           else
+               "From the shadowy landing, you can see much of the empty
+                foyer stretching out below you.";
+       ],
+       name 'foyer',
+  has  ;
+
+!-----------------------------------------------
+
+Room  ground_corridor "First Floor Corridor"
+  with  name 'first' 'floor' 'ground' 'corridor',
+        description [;
+            print "A long north-south corridor, much the same as
+                   those on the other floors. ";
+            print "Three gray doors line the eastern wall. The first two have small
+                   glass windows, peering into darkened laboratories. The third ";
+            if (ground_equipment_door has open)
+                print "is open onto an equipment room.^";
+            else 
+                print "is plain and leads to a small equipment room. All three are closed.^";
+        ],
+        s_to ground_door,
+        se_to saunders_door,
+        e_to pooley_door,
+        ne_to ground_equipment_door,
+        cant_go "The only exits are the three doors lining
+                 the corridor (south-east, east and north-east) and the automatic door
+                 back to the foyer (south).",
+        lower_name "the first floor corridor",
+  has   ;
+
+FakeDoor  saunders_door "door to the Saunders Lab" ground_corridor
+  with  name 'door' 'grey' 'gray' 'saunders' 'first' 'lab' 'se' 'south-east',
+        description "A gray door with a small glass window,
+                     looking into a darkened lab.
+                     A small plaque reads: 'Saunders Lab'.",
+  has   locked scenery;
+
+FakeDoor  pooley_door "door to the Pooley Lab" ground_corridor
+  with  name 'door' 'grey' 'gray' 'pooley' 'second' 'lab' 'e\\' 'east',
+        description "A gray door with a small glass window,
+                     looking into a darkened lab.
+                     A small plaque reads: 'Pooley Lab'.",
+  has   locked scenery;
+  
+Prop   door_window "small glass window"
+  with  name 'small' 'glass' 'window' 'windows',
+        description "You can't see anything of interest through the glass.",
+        before [;
+            Take,PushDir:
+                print_ret (The) self, " is fixed in the door.";
+            Unlock:
+                if (IsOfType(second,crowbar))
+                    <<Attack self>>;
+                else
+                    "The embedded window does not open.";
+            Open:
+                "The embedded window does not open.";            
+            Attack:
+              if (AmHolding(crowbar)) {
+                  print "You swing the crowbar firmly into the small window, 
+                         but it barely leaves a mark.^";
+                  return true;
+              }
+              else
+                "You don't have anything heavy enough to break the window with.";
+            Search:
+              <<Examine self>>;             
+        ],  
+        found_in ground_corridor basement_corridor,
+  has   scenery concealed lockable;
+  
+PluralSight doors_in_ground_corridor "doors" ground_corridor
+  with  name 'doors',
+        description [;
+              print "There are three doors on the eastern wall of the corridor, 
+                     the first two (to the south-east and east) lead to the Saunders
+                     and Pooley labs. The third (to the north-east) ";
+              if (ground_equipment_door has open)
+                  print "is open and ";
+              print "leads to a small equipment room. To the south, the plate glass
+                     automatic door to the foyer ";
+              if (ground_door has open)
+                  print "lies open.^";
+              else
+                  print "stands closed.^";
+        ],
+  has   pluralname;
+
+!-----------------------------------------------
+
+Room  basement_corridor "Basement Corridor"
+  with  name 'basement' 'corridor',
+        description [;
+            print "A long north-south corridor, much the same as
+                   those on the other floors. ";
+            print "Three gray doors line the eastern wall. The first two have small
+                   glass windows, peering into darkened laboratories. The third ";
+            if (basement_equipment_door has open)
+                print "is open onto an equipment room.^^";
+            else 
+                print "is plain and leads to a small equipment room. All three are closed.^^";
+            if (deutsch_door has open)
+                print "At the north end is an
+                       open door leading to the Deutsch lab.^";
+            else
+                print "At the north end a fourth door leads to
+                       the Deutsch lab.^";
+        ],
+        s_to basement_door,
+        se_to bostrom_door,
+        e_to wallace_door,
+        ne_to basement_equipment_door,
+        n_to deutsch_door,
+        cant_go "The only exits are to the Deutsch lab (north) the three doors lining
+                 the corridor (south-east, east and north-east) and the automatic door
+                 back to the landing (south).",
+        lower_name "the basement corridor",
+  has   ;
+
+FakeDoor  bostrom_door "door to the Bostrom Lab" basement_corridor
+  with  name 'door' 'grey' 'gray' 'bostrom' 'first' 'lab' 'se' 'south-east',
+        description "A gray door with a small glass window,
+                     looking into a darkened lab.
+                     A small plaque reads: 'Bostrom Lab'.",
+  has   locked scenery;
+
+FakeDoor  wallace_door "door to the Wallace Lab" basement_corridor
+  with  name 'door' 'grey' 'gray' 'wallace' 'second' 'lab' 'e\\' 'east',
+        description "A gray door with a small glass window,
+                     looking into a darkened lab.
+                     A small plaque reads: 'Wallace Lab'.",
+  has   locked scenery;
+
+PluralSight doors_in_basement_corridor "doors" basement_corridor
+  with  name 'doors',
+        description [;
+              print "There are three doors on the eastern wall of the corridor, 
+                     the first two (to the south-east and east) lead to the Bostrom
+                     and Wallace labs. The third (to the north-east) ";
+              if (basement_equipment_door has open)
+                  print "is open and ";
+              print "leads to a small equipment room. At the north end is the ";
+              if (deutsch_door has open)
+                  print "open ";
+              print "door to the Deutsch lab. ";
+              print "To the south, the plate glass automatic door to the landing ";
+              if (basement_door has open)
+                  print "lies open.^";
+              else
+                  print "stands closed.^";
+        ],
+  has   pluralname;
+
+!-----------------------------------------------
+
+Room  upstairs_corridor "Second Floor Corridor"
+  with  description
+            "A long north-south corridor, much the same as
+             those on the other floors. Three plain gray doors line the eastern wall.",
+        n_to balcony_door,
+        ne_to conference_door,
+        e_to butterfield_door,
+        se_to brown_door,
+        s_to upstairs_door,
+        cant_go "The only exits are to the balcony (north) the three doors lining
+                 the corridor (south-east, east and north-east) and the automatic door
+                 back to the landing (south).",
+        lower_name "the second floor corridor",
+  has   ;
+
+FakeDoor  brown_door "door to Dr Brown's office" upstairs_corridor
+  with  name 'door' 'grey' 'gray' 'brown' 'office' 'brown^s' 'Dr' 'first' 'se' 'south-east',
+        description "A simple gray door.
+                     A small plaque reads: 'Dr Brown'.",
+  has   locked scenery;
+
+FakeDoor  butterfield_door "door to Professor Butterfield's office" upstairs_corridor
+  with  name 'door' 'office' 'grey' 'gray' 'butterfield' 'butterfield^s' 'Prof' 'second'
+             'e\\' 'east',
+        description "A simple gray door.
+                     A small plaque reads: 'Prof Butterfield'.",
+  has   locked scenery;
+
+FakeDoor  conference_door "door to the conference room" upstairs_corridor
+  with  name 'door' 'grey' 'gray' 'conference' 'third' 'ne' 'north-east',
+        description "A plain gray door.
+                     A small plaque reads: 'Conference Room'.",
+        found_in upstairs_corridor conference_room,
+  has   locked scenery;
+
+PluralSight doors_in_upstairs_corridor "doors" upstairs_corridor
+  with  name 'doors',
+        description [;
+              print "There are three doors on the eastern wall of the corridor, 
+                     the first two (to the south-east and east) lead to Dr Brown
+                     and Professor Butterfield's offices. The third (to the north-east) 
+                     leads to the conference room. At the north end is the ";
+              if (balcony_door has open)
+                  print "open ";
+              print "glass door to the balcony. ";
+              print "To the south, the plate glass automatic door to the landing ";
+              if (upstairs_door has open)
+                  print "lies open.^";
+              else
+                  print "stands closed.^";
+        ],
+  has   pluralname;
+
+!-----------------------------------------------
+
+Room  deutsch_lab "The Deutsch Laboratory"
+  with  name 'lab' 'deutsch' 'laboratory',
+        description [;
+            if (self hasnt visited) {
+                print "The lab is order and chaos. By the dim blue-green light of a few swirling
+                screen savers, you can see the cluttered benches of your colleagues, frozen in the
+                mess of academic creativity. Frozen exactly as they were when badges were flashed,
+                when we looked on in disbelief as they took control of the lab. Yours however, is clean.
+                The books and papers are in neat stacks. They have been working here.^
+                ^
+                Nearby, against the north wall is the prototype, a six foot cylinder of brushed steel cladding.
+                The door has been taken off and is nowhere to be seen. They have been working on it too.
+                You wince at the sight.^";
+
+                if (deutsch_door has open)
+                    print "^To the south, the door to the lab lies open.^";
+                else
+                    print "^To the south, the door to the lab stands closed.^";     
+                
+                return true;
+            }
+            print "The lab is order and chaos. By the dim blue-green light of a few swirling
+                screen savers, you can see the cluttered benches of your colleagues, frozen in the
+                mess of academic creativity. Yours however, is clean.
+                The books and papers are in neat stacks. They have been working here.^
+                ^
+                Nearby, against the north wall is the prototype, a six foot cylinder of brushed steel cladding.
+                They have been working on it too.
+                The door has been taken off and is nowhere to be seen.^";
+                
+            if (deutsch_door has open)
+                "^To the south, the door to the lab lies open.";
+            else
+                "^To the south, the door to the lab stands closed.";
+        ],
+        out_to deutsch_door,
+        s_to deutsch_door,
+        in_to prototype_interior,
+        cant_go "The only exits are to the south and in to the prototype.",
+        lower_name "the Deutsch laboratory",
+  has   proper;
+
+  
+Object  prototype "prototype"
+  with  description [;
+            if (~~prototype_seen) {
+                prototype_seen = true;
+                print "You had built the prototype to get a strong negative result,
+                    to show that the standard model of Quantum Mechanics
+                    led to demonstrably false claims involving reverse causation. You were mistaken.
+                    One by one, your experiments showed your preliminary calculations to have been correct.
+                    When the military removed you from your project, only one aspect
+                    remained untested  -- an aspect
+                    you had been loath to test before you could predict the results -- inconsistent observation.^
+                    ^
+                    What would happen if anomalies were observed by those in the original
+                    time-line? Your prior experiments had heavily shielded the prototype from outside interaction
+                    to avoid the very possibility. And as the calculations came out time and again,
+                    that is the only reason you are alive today.
+                    When an observer in the original time-line has an anomalous observation, the wave
+                    function of the temporally relocated object collapses and the relocation retrospectively fails,
+                    preserving chronological consistency. There is just one side effect:
+                    total transformation of the object's mass into a burst of photons -- pure energy.^
+                    ^
+                    You tried to tell them over and again. They assumed you were merely jealous of the takeover.
+                    Now, the night before their scheduled 'first main experiment', you have come to 
+                    put an end to it all. To destroy your prototype and avoid tomorrow's nightmare.^
+                    ^
+                    The prototype itself is a six foot tall, four foot wide cylinder, clad with
+                    brushed steel. The frame and door were fitted with quantum shielding
+                    to prevent decoherence of the wave function, but now the door has been
+                    removed and any use of the machine is potentially disastrous.^";
+            }
+            else 
+                print "The prototype is a six foot tall, four foot wide cylinder clad with
+                       brushed steel. The frame and door were fitted with quantum shielding
+                       to prevent decoherence of the wave function, but now the door has been
+                       removed and any use of the machine is potentially disastrous.^";
+            if (~~(self.fixed))
+                "^On close inspection, it appears that an attempt is in progress
+                 to move the control panel so that it can be operated from the inside.
+                 As it is, the prototype is currently not functioning, but you think
+                 you could probably complete the modification within a minute or two.";
+            return true;
+        ],
+        name 'prototype' 'time' 'machine' 'six' 'foot' 'cylinder',
+        fixed,
+        before [t;
+          Set:
+            if (self.fixed) {
+                if (self in deutsch_lab)
+                    "The prototype has been modified so that the only way to operate it is
+                     to enter it and use the internal control panel.";
+                if (self in prototype_interior)
+                    <<Set control_panel>>;
+            }
+            else
+                "You will need to complete the partial modifications to use the prototype.";
+          SetTo:
+            if (self.fixed) {
+                if (self in deutsch_lab)
+                    "The prototype has been modified so that the only way to operate it is
+                     to enter it and use the internal control panel.";
+                if (self in prototype_interior)
+                    <<SetTo control_panel second>>;
+            }
+            else
+                "You will need to complete the partial modifications to use the prototype.";
+          SwitchOn:
+            if (self.fixed) {
+                if (self in deutsch_lab)
+                    "The prototype has been modified so that the only way to operate it is
+                     to enter it and use the internal control panel.";
+                if (self in prototype_interior) {
+                    print "(pressing the silver button)^";
+                    <<Push silver_button>>;
+                }
+            }
+            else
+                "You will need to complete the partial modifications to use the prototype.";
+          Enter:
+            <<Go in_obj>>;
+          Exit:
+            if (real_location == prototype_interior)
+                   <<Go out_obj>>;
+          Tie:
+            if (~~d_paradox) {
+                if (second == nothing) {
+                    if (self.fixed)
+                        "It is already fixed.";
+                    if (AmHolding(cable)) {
+                        if (self in deutsch_lab) {
+                            print "(first entering the prototype)^";
+                            <Go in_obj>;
+                            IncTime();
+                            if (Stopped()) return true;
+                            print "^";
+                        }
+                        move GetHeld(cable) to limbo;
+                        print "You begin work completing the modifications...^";
+                        for (t=0 : t<10 : t++) {
+                            IncTime();
+                            if (Stopped()) return true;
+                        }
+                        self.fixed = true;
+                        prototype_fixed_time = my_time;
+                        print "After a minute or so, you are done.^";
+                        return true;
+                    }
+                    else
+                        "After a few moments, you realise that completing the modification
+                         will require a ribbon cable to connect the components. You know the
+                         type of cable well, but don't have any in the lab right now.
+                         Still, the equipment room in the corridor should have one.";          
+                }
+            }
+          Attack:
+            "It won't be enough to smash the prototype by hand as there are too many
+             circuits buried away inside that would not be harmed.
+             Besides, that is why you brought the bomb.";
+          Search:
+            if (self in deutsch_lab) {
+                print "(first entering the prototype)^";
+                <<Go in_obj>>;
+            }
+            else
+                <<Look>>;
+        ],
+        react_before[;
+          Insert:
+            if (~~(self.fixed))
+                if (IsOfType(noun,cable))
+                    if ((second == self) || (second == control_panel))
+                        <<Tie prototype>>;
+            if (second == self) {
+                if (noun == self)
+                    "It wont fit. Obviously. What were you thinking? It is a prototype
+                     chrono-transference device, not some kind of TARDIS.";
+                if (self in deutsch_lab) {
+                    move noun to prototype_interior;
+                    print "You reach in and place ", (the) noun, " inside the prototype.^";
+                    return true;
+                }
+                else
+                    <<Drop noun>>;
+            }
+        ],
+        found_in deutsch_lab prototype_interior,
+  has   scenery concealed;
+
+Furniture  bench "your bench" deutsch_lab
+  with  description "Your bench has clearly been used recently, and not by you.",
+        before [;
+          Examine:
+            print "Your bench has clearly been used recently, and not by you.
+                   Your books and papers are neatly piled to one side, leaving
+                   the largest expanse of bare desk you have ever seen here.^";
+            if (~~have_looked_at_bench) {
+                have_looked_at_bench = true;
+                "^You suddenly notice that your research notes are not here.
+                 You were sure they would be -- and would thus be destroyed in the blast.
+                 This is bad. Very bad.";
+            }
+            return true;
+          Search:
+            <<Examine self>>;
+        ],
+        name 'bench' 'your' 'benches' 'table' 'desk',
+  has   scenery proper;
+
+Prop books "text books" deutsch_lab
+  with  description "A few texts on Quantum Mechanics and String Theory
+                     that have served you very well.",
+        name 'books' 'book' 'texts',
+  has;
+
+Prop papers "papers" deutsch_lab
+  with  description [;
+            print "A collection of photocopied journal papers that you had been reading
+                   a few weeks ago.^";
+            if (~~have_looked_at_bench) {
+                have_looked_at_bench = true;
+                "^You suddenly notice that your research notes are not here.
+                 You were sure they would be -- and would thus be destroyed in the blast.
+                 This is bad. Very bad.";
+            }
+            return true;
+        ],
+        name 'papers' 'photocopies' 'stack' 'stacks',
+  has;
+
+Prop screen_savers "screen savers" deutsch_lab
+  with  description "Abstract, organic shapes leave glowing phosphor trails as they swirl around
+                     and through themselves.",
+        name 'screen' 'screens' 'saver' 'savers' 'computer' 'computers' 'light' 'violet' 'green' 'blue'
+             'blue-green' 'swirling',
+  has;
+
+Prop cladding "cladding" deutsch_lab
+  with  name 'cladding' 'steel' 'brushed' 'frame' 'hatch',
+  has;
+
+Prop mess "mess" deutsch_lab
+  with  description "The usual academic mess -- open books, coffee stained mugs, sprawling papers
+                     -- frozen in time.",
+        name 'mess' 'chaos',
+  has;
+
+Sight control_panel_from_lab "control panel" deutsch_lab
+  with  description "You cannot see the control panel clearly from here, and would need to enter the prototype.",
+        name 'control' 'panel',
+        before [;
+            Push:
+                <<Tie prototype>>;
+            Examine:
+                "You cannot see the control panel clearly from here, and would need to enter the prototype.";
+            default:
+                "You would have to enter the prototype to do that.";
+        ],
+  has;
+
+!-----------------------------------------------
+
+Room  prototype_interior "Inside the prototype"
+  with  description [;
+            if (prototype.fixed) {
+                print "The interior of the prototype is cramped and dark.
+                       On the wall you see the control panel with a small LED timer
+                       set to ", control_panel.time_value, " seconds, and a silver button.
+                       Through the open hatch you can see some of the Deutsch lab.^";
+            }
+            else
+                "The interior of the prototype is cramped and dark. 
+                 On the wall you can see the half-installed control panel.
+                 Through the open hatch you can see some of the Deutsch lab.";
+         ],
+        name 'prototype' 'time' 'machine' 'interior',
+        out_to deutsch_lab,
+        lower_name "the prototype",
+        cant_go "The only exit is out to the Deutsch lab.",
+  has proper;
+
+Object control_panel "control panel" prototype_interior
+  with  name 'control' 'panel' 'led' 'timer' 'time' 'screen', 
+        description [;
+            print "A brushed steel control panel with a blue LED timer, set to ", 
+                   control_panel.time_value, " seconds, and a shiny silver button.^";
+            ],
+        time_value,
+        before [;
+          Push:
+            <<Tie prototype>>;
+          Set:
+            if (prototype.fixed)
+                "To set the control panel,
+                 you need to specify a number of seconds,
+                 for example, with 'set panel to 75'.";
+            else
+                "You won't be able to set the control panel
+                 until you complete the modifications.";
+          SetTo:
+            if (prototype.fixed) {
+                if (second > 0 && second <= 500) {
+                    self.time_value = second;
+                    "You quickly type the number in to the control panel.";
+                }
+                else {
+                    "The prototype's control panel only accepts
+                     between 1 and 500 seconds.";
+                }
+            }
+            else
+                "You won't be able to set the control panel
+                 until you complete the modifications.";
+          SwitchOn:
+            if (self.fixed) {
+                print "(pressing the silver button)^";
+                <<Push silver_button>>;
+            }
+            else
+                "You will need to complete the partial modifications to use the prototype.";
+        ],
+  has scenery concealed;
+
+Object silver_button "silver button" prototype_interior
+  with  name 'button' 'silver' 'silvered',
+        description "A silvered button.",
+        before [old_value t;
+          Push:
+            if (prototype.fixed) {
+                if (control_panel.time_value == 0)
+                    "The control panel emits a small beep and the number '0'
+                     flashes out at you. Perhaps you should set it first.";
+                else if (time_travelled < MAX_TIME_TRAVELS) {
+                    old_value = control_panel.time_value;
+                    TravelThroughTime(control_panel.time_value);
+                    if (deadflag)
+                        return true;
+                    for (t=0 : t < time_travelled : t++)
+                        if ((Get2D(player_loc,t,my_time-EARLIEST_TIME) == deutsch_lab) ||
+                            (Get2D(player_loc,t,my_time-EARLIEST_TIME) == prototype_interior))
+                                "You hold your breath and activate the prototype.";
+                                ! this is needed to avoid silly message below, then death
+                    if ((old_value % 5) ~= 0)
+                        "You pause for a moment after pressing the button,
+                         carefully resynchronizing yourself with the 
+                         five second turn increments.";
+                    else 
+                        "You hold your breath and activate the prototype.";
+                }
+                else
+                    "Nothing happens.";
+            }
+            else
+                "The button won't work
+                 until you complete the modifications.";
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+  has scenery concealed;
+
+Sight deutsch_lab_from_prototype "Deutsch lab" prototype_interior
+  with  description "You can't make out much of interest from here, just a few benches
+                     under the shifting blue-violet-green light.",
+        name 'deutsch' 'lab' 'hatch' 'bench' 'benches',
+  has;
+
+Prop surface "inside surface" prototype_interior
+  with name 'walls' 'interior' 'surface' 'ceiling' 'floor' 'ground',
+       description "The interior of the prototype is clad
+                    in smooth brushed steel.",
+  has  ;
+!-----------------------------------------------
+
+Room  basement_equipment "Basement Equipment Room"
+  with  name 'equipment' 'room',
+        description [;
+            if (FlashLit()) {
+                MoveMoveableChildren(basement_equipment_gloom,self);
+                print "By the thin blue-white beam of your flashlight, you
+                       see the crowded shelves of the equipment room.^";
+                if (basement_equipment_door has open)
+                    print "^To the west, the door to the corridor lies open.^";
+                else
+                    print "^To the west, the door to the corridor stands closed.^";
+            }
+            else {
+                MoveMoveableChildren(self,basement_equipment_gloom);
+                if (basement_equipment_door has open)
+                    print "It is almost completely dark. Some faint light spills
+                           in from the west through the open door, allowing you to just
+                           discern the outlines of a series of shelves. By the door is
+                           a light switch.^";
+                else
+                    print "You are in complete darkness.^";
+            }
+        ],
+        out_to basement_equipment_door,
+        w_to basement_equipment_door,
+        sw_to [;<<Go w_obj>>;],
+        cant_go "The only exit is westwards, back to the corridor.",
+        lit false,
+        has_been_lit false,
+        lower_name "the basement equipment room",
+  has   ;
+
+! A behind-the-scenes 'room' to store the items that should be hidden while the
+! basement equipment room is in darkness
+
+Room  basement_equipment_gloom "Dark Basement Equipment Room"
+  with  name 'equipment' 'room' 'dark',
+        lower_name "the dark basement equipment room",
+  has   ;
+  
+Object basement_light_switch "light switch" basement_equipment
+  with  name 'switch' 'light' 'lights',
+        before [;
+          Push:
+            <<SwitchOn basement_light_switch>>;
+          SwitchOn:
+            if (~~self.blown) {
+                Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,BLOW_BASEMENT_LIGHT_);
+                self.blown = true;
+                if (FlashLit())
+                    "The fluorescent lights flicker hopefully, strobing rapidly across the
+                     scattered equipment. Then darkness. You blink away the after-images
+                     and are left with only the faint torchlight.";
+                else
+                    "The fluorescent lights flicker hopefully, strobing rapidly across the
+                     scattered equipment. Then darkness. Nothing but a few fleeting
+                     after-images of the cluttered room.";                
+            }
+            else
+                "Click. Nothing happens.";
+        ],
+        react_before [;
+          Go:
+            MoveMoveableChildren(basement_equipment,basement_equipment_gloom);
+        ],
+        react_after [;
+          Drop:
+            if (~~(FlashLit())) {
+                move noun to basement_equipment_gloom;
+            }
+          Go:
+            if (basement_equipment.lit || FlashLit()) {
+                MoveMoveableChildren(basement_equipment_gloom,basement_equipment);
+            }
+        ],
+        blown false,
+  has static scenery concealed switchable;
+  
+!-----------------------------------------------
+
+Room  ground_equipment "First Floor Equipment Room"
+  with  name 'equipment' 'room',
+        description [;
+            if (self.lit) {
+                MoveMoveableChildren(ground_equipment_gloom,self);
+                print "By the flickering fluorescent lights, you
+                       see the crowded shelves of the equipment room.^";
+                if (ground_equipment_door has open)
+                    print "^To the west, the door to the corridor lies open.^";
+                else
+                    print "^To the west, the door to the corridor stands closed.^";
+            }
+            else {
+                if (FlashLit()) {
+                    MoveMoveableChildren(ground_equipment_gloom,self);
+                    print "By the thin blue-white beam of your flashlight, you
+                           see the crowded shelves of the equipment room.^";
+                    if (ground_equipment_door has open)
+                        print "^To the west, the door to the corridor lies open.^";
+                    else
+                        print "^To the west, the door to the corridor stands closed.^";
+                }
+                else {
+                    MoveMoveableChildren(self,ground_equipment_gloom);
+                    if (ground_equipment_door has open)
+                        print "It is almost completely dark. Some faint light spills
+                               in from the west through the open door, allowing you to just
+                               discern the outlines of a series of shelves. By the door is
+                               a light switch.^";
+                    else
+                        print "You are in complete darkness.^";
+                }
+            }
+        ],
+        out_to ground_equipment_door,
+        w_to ground_equipment_door,
+        sw_to [;<<Go w_obj>>;],
+        cant_go "The only exit is westwards, back to the corridor.",
+        lit false,
+        has_been_lit false,
+        lower_name "the first floor equipment room",
+  has   ;
+
+Room  ground_equipment_gloom "Dark First Floor Equipment Room"
+  with  name 'equipment' 'room' 'dark',
+        lower_name "the dark first floor equipment room",
+  has   ;
+
+Object ground_light_switch "light switch" ground_equipment
+  with  name 'switch' 'light' 'lights',
+        before [;
+          Push:
+            if (~~ground_equipment.lit) {
+                <<SwitchOn ground_light_switch>>;
+            }
+            else {
+                <<SwitchOff ground_light_switch>>;
+            }
+          SwitchOn:
+            if (~~ground_equipment.lit) {
+                ground_equipment.lit = true;
+                give self on;
+                print "The lights come on after a brief flicker.^";
+                <Look>;
+                instant_action_this_turn = false;
+                return true;
+            }
+          SwitchOff:
+            if (ground_equipment.lit) {
+                ground_equipment.lit = false;
+                give self ~on;
+                if (FlashLit())
+                    "The lights flicker briefly, then go out,
+                     leaving you in the faint torchlight.";                  
+                else {
+                    MoveMoveableChildren(ground_equipment,ground_equipment_gloom);
+                    "The lights flicker briefly, then go out,
+                     leaving you in the darkness.";
+                }
+            }
+        ],
+        react_before [;
+          Go:
+            if (~~(ground_equipment.lit))
+                MoveMoveableChildren(ground_equipment,ground_equipment_gloom);
+        ],
+        react_after [;
+          Drop:
+            if (~~(ground_equipment.lit || FlashLit())) {
+                move noun to ground_equipment_gloom;
+            }
+          Go:
+            if ((ground_equipment.lit) || FlashLit()) {
+                MoveMoveableChildren(ground_equipment_gloom,ground_equipment);
+            }
+        ],
+  has static scenery concealed switchable;
+
+Prop  shelves "shelves"
+  with  name 'shelf' 'shelves' 'equipment' 'series' 'outlines' 'outline' 'clutter' 'cluttered',
+        description [;
+            if (((parent(self)).lit) || (Flashlit()))
+                "The shelves are filled with assorted lab equipment, but nothing of use
+                 to you now.";
+            else
+                "You cannot make out any of the objects on the dark shelves.";
+        ],
+        found_in ground_equipment basement_equipment,
+  has   ;
+
+Prop  fluoro_light "fluorescent lights"
+  with  name 'fluoro' 'fluorescent' 'flicker' 'flickering' 'tube',
+        description [;
+            if ((parent(self)).lit) 
+                "The fluorescent tubes flicker brightly.";
+            else
+                "You can just make out a dark fluorescent tube in the ceiling above.";
+        ],
+        found_in ground_equipment basement_equipment,
+  has   ;
+
+!-----------------------------------------------
+
+Room  balcony "Balcony"
+  with  name 'balcony',
+        description
+            "A wide balcony, looking out over the sleeping city. Below you, a lawn slopes gently away
+             into the gloom, a few silhouetted trees marking the edge of the modest grounds. Above, the
+             clear sky is a deep black, dusted with glinting stars.",
+        d_to [;Jumped(); return true;],
+        n_to [;Jumped(); return true;],
+        s_to balcony_door,
+        se_to conference_window,
+        in_to conference_window,
+        cant_go [;
+            if (conference_window has open)
+                "The only exits are the door back to the corridor (to the south)
+                 and the window into the conference room (to the south-east).";
+            else
+                "The only exit is the door back to the corridor (to the south).";
+        ],
+        lower_name "the balcony",
+  has   ;
+
+Prop   balcony_floor "floor" balcony
+  with name 'floor' 'ground' 'tiles',
+       description "The floor is covered in white tiles.",
+  has  ;
+
+Prop   railing "railing" balcony
+  with name 'rail' 'railing' 'hand' 'handrail',
+  has  ;
+
+Sight  trees "trees" balcony
+  with name 'tree' 'trees' 'silhouette' 'silhouettes' 'cypress' 'cypresses' 'conifer' 'conifers',
+       description "The trees are some kind of tall conifer, cypress perhaps. You have fond
+                    memories of dozing under them one afternoon last summer.",
+  has  ;
+
+Sight  grounds "grounds" balcony
+  with name 'lawn' 'slope' 'slopes' 'grounds' 'grass' 'gloom',
+       description "The grounds are little more than a well-kept lawn and a few tall trees, but
+                    every night the security guard has to give them a brief inspection.",
+  has  ;
+
+Sight  guard "guard" balcony
+  with name 'guard' 'security' 'guards',
+       description "There is no sign of the security guard.",
+  has  ;
+
+Sight  stars "stars"
+  with name 'stars' 'star' 'black' 'dust' 'constellations',
+       description "The stars are a beautiful spray of glinting jewels in the blackness above.",
+       found_in balcony conference_room,
+  has  ;
+
+Sight  night "night"
+  with name 'night' 'starry',
+       description "Outside, it is one of the finest fall nights you can recall.",
+       found_in balcony conference_room,
+  has  ;
+
+Sight  city "city"
+  with name 'city' 'boston' 'town' 'light' 'rooftops' 'roofs' 'skyscrapers' 'buildings' 'building',
+       description "Before you, lie the rooftops and skyscrapers of your home town. Here and there
+                    a small yellow light glows, but for now Boston sleeps.",
+       found_in balcony conference_room,
+  has  ;
+
+
+!-----------------------------------------------
+
+Room  conference_room "Conference Room"
+  with  name 'conference',
+        description "A rather slick but soulless affair. A large table of dark polished wood
+                     takes pride of place and is surrounded by a half-dozen chairs.",
+        n_to conference_window,
+        nw_to conference_window,
+        out_to conference_window,
+        w_to conference_door,
+        cant_go "The only exits are the door to the west and the window to the north.",
+        lower_name "the conference room",
+  has   ;
+  
+Sight  conference_room_sight "room" conference_room
+  with name 'room' 'conference',
+       description "A rather slick but soulless affair.",
+       before [;
+         Exit:
+             <<Go n_obj>>;
+       ],
+  has  ;
+
+Furniture  conference_table "conference table" conference_room
+  with  description "A large round table of dark polished wood.",
+        name 'table' 'round' 'large' 'polished' 'dark' 'wood',
+  has   scenery;
+
+Furniture  chair "chair" conference_room
+  with  description "Each chair is of a rather elegant, modern design
+                     in the same dark wood as the table.",
+        name 'chair' 'chairs' 'seat' 'seats',
+  has   scenery concealed;
+
+!-----------------------------------------------
+
+Room  outside "Outside"
+  with  description "Outside the lab, the street is quiet.",
+        n_to main_doors,
+        lower_name "the night",
+  has   ;
+
+!-----------------------------------------------
+
+Room  limbo "Night"
+  with  description "The waiting place for unrealised items.",
+        lower_name "the night",
+  has   ;
+
+
+!------------------------------------------------------------------------
+!
+!  Door stuff
+!
+
+AutomaticDoor  main_doors "main doors" foyer
+  with  description [;
+           if (self has open)
+               print "Through the open doors, you can see the quiet grounds.
+                      On the right hand side is a green button.^";
+           else
+               print "A pair of ";
+               if (self.smashed) print "cracked ";
+               print "plate glass sliding doors, 
+                      through which you can see the quiet grounds.
+                      On the right hand side is a green button.^";
+        ],
+        when_closed "To the south is a set of automatic doors leading
+                    out into the inky night.",
+        when_open "To the south is an open set of automatic doors leading
+                    out into the inky night.",
+        name 'doors' 'main' 'south' 'plate' 'glass' 'sliding' 'set' 'auto',
+        door_to [;Escaped(); return true;],
+        door_dir s_to,
+        open_self [t;
+            if (self hasnt open) {
+                give self open ~locked;
+                if (self in LocationOf(player))
+                    print "The main doors open onto the night.^";
+            }
+            self.to_close_at = t;
+            if ((player in foyer) && (my_time < start_time-1) && (my_time >= start_time-3)) {
+                d_paradox = true;
+                deadflag = 3;
+                Seperator();
+                print "Outside, your former self darts quickly towards the main doors.
+                       When she sees them open, she breaks her stride
+                       and lets out a shocked gasp.^";
+                print "^Time unravels...^";
+                Devours(my_time);   
+            }
+        ],
+        closing_message [;
+            if ((~~Stopped()) && (self in LocationOf(player)))
+                "The main doors softly slide closed.";
+        ],
+        before [; 
+        Open:
+            print "(pressing the green exit button)^";
+            <<Push exit_button>>;
+        Unlock:
+           if (IsOfType(second,crowbar))
+               <<Attack self>>;
+           else
+               "You cannot open the door with that.";
+        Enter:
+          if (self hasnt open) {
+              print "(first pressing the green exit button)^";
+              <Push exit_button>;
+              IncTime();
+              if (Stopped()) return true;
+              <<Go s_obj>>;
+          }
+        ],
+        react_before [; Go:
+            if (noun == s_to && self hasnt open)
+                <<Enter self>>;
+        ],
+  has   pluralname;
+
+
+AutomaticDoor  ground_door "automatic door"
+  with  description [;
+          if (self in foyer) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_GROUND_CORRIDOR_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see a dim corridor. ";
+              if (IsIn(former_self,ground_corridor))
+                  print "In the shadows stands your past self. ";
+              print "On the right hand side is a slot for an ID card.^";
+          }
+          if (self in ground_corridor) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_FOYER_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see the darkened foyer. ";
+              if (IsIn(former_self,foyer))
+                  print "In the shadows stands your past self. ";
+              print "On the right hand side is a green button.^";
+          }
+        ],
+        when_closed [;
+          if (self in foyer)
+                    "In the north wall is a closed
+                     automatic door.";
+          if (self in ground_corridor)
+                    "To the south is a closed automatic door, leading back
+                     to the foyer.";
+
+        ],
+        when_open [;
+          if (self in foyer)
+                    "In the north wall is an open
+                     automatic door.";
+          if (self in ground_corridor)
+                    "To the south is an open automatic door, leading back
+                     to the foyer.";
+
+        ],
+        name 'north' 'door' 'automatic' 'auto' 'plate' 'glass' 'sliding',
+        door_to [;
+          if (self in foyer)
+              return ground_corridor;
+          if (self in ground_corridor)
+              return foyer;
+
+        ],
+        door_dir [;
+          if (self in foyer)
+              return n_to;
+          if (self in ground_corridor)
+              return s_to;
+
+        ],
+        before [; 
+        Unlock:
+           if (IsOfType(second,crowbar))
+               <<Attack self>>;
+           else if (IsOfType(second,id_card) && (self in foyer))
+               <<Insert second id_slot>>;
+           else
+               "You cannot open the door with that.";
+        Open:
+          if (self in foyer)
+              if (self.known_exterior_opening == 0)
+                  "There is no obvious way to get 
+                   the automatic door to open.";
+              else {
+                  print "You press the button marked 'first'.^";
+                  <<Push first_button>>;
+              }
+          if (self in ground_corridor) {
+              print "(pressing the green exit button)^";
+              <<Push exit_button>>;
+          }
+        Enter:
+          if (self in ground_corridor && self hasnt open) {
+              print "(first pressing the green exit button)^";
+              <Push exit_button>;
+              IncTime();
+              if (Stopped()) return true;
+              <<Go s_obj>>;
+          }
+          if (self in foyer && self hasnt open) {
+              if (self.known_exterior_opening == true)  {
+                  print "(first pressing the button marked 'first')^";
+                  <Push first_button>;
+                  IncTime();
+                  if (Stopped()) return true;
+                  <<Go n_obj>>;
+              }
+              else {
+                  "There is no obvious way to get 
+                   the automatic door to open.";
+              }
+          }
+        ],
+        react_before [; Go:
+            if (noun == n_to && self in foyer && self hasnt open)
+                <<Enter self>>;
+            if (noun == s_to && self in ground_corridor && self hasnt open)
+                <<Enter self>>;
+        ],
+        known_exterior_opening,
+        found_in foyer ground_corridor,
+  has  ;
+
+
+AutomaticDoor  basement_door "automatic door"
+  with  description [;
+          if (self in basement_landing) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_BASEMENT_CORRIDOR_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see a dim corridor. ";
+              if (IsIn(former_self,basement_corridor))
+                  print "In the shadows stands your past self. ";
+              print "On the right hand side is a slot for an ID card.^";
+          }
+          if (self in basement_corridor) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_BASEMENT_LANDING_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see the small basement landing. ";
+              if (IsIn(former_self,basement_landing))
+                  print "In the shadows stands your past self. ";
+              print "On the right hand side is a green button.^";
+          }
+        ],
+        name 'door' 'automatic' 'auto' 'plate' 'glass' 'sliding',
+        when_closed [;
+          if (self in basement_landing)
+                    "To the north is a closed automatic door.";
+          if (self in basement_corridor)
+                    "To the south is a closed automatic door, leading back
+                     to the landing.";
+
+        ],
+        when_open [;
+          if (self in basement_landing)
+                    "To the north is an open automatic door.";
+          if (self in basement_corridor)
+                    "To the south is an open automatic door, leading back
+                     to the landing.";
+
+        ],
+        door_to [;
+          if (self in basement_landing)
+              return basement_corridor;
+          if (self in basement_corridor)
+              return basement_landing;
+
+        ],
+        door_dir [;
+          if (self in basement_landing)
+              return n_to;
+          if (self in basement_corridor)
+              return s_to;
+
+        ],
+        before [; 
+        Unlock:
+           if (IsOfType(second,crowbar))
+               <<Attack self>>;
+           else if (IsOfType(second,id_card) && (self in basement_landing))
+               <<Insert second id_slot>>;
+           else
+               "You cannot open the door with that.";
+        Open:
+          if (self in basement_landing) {
+              if ( AmHolding(id_card) ) {
+                  print "(inserting your ID card)^";
+                  <<Insert (GetHeld(id_card)) id_slot>>;
+              }
+              else
+                  "You would need you ID card to do that.";
+          }
+          if (self in basement_corridor) {
+              print "(pressing the green exit button)^";
+              <<Push exit_button>>;
+          }
+        Enter:
+          if (self in basement_corridor && self hasnt open) {
+              print "(first pressing the green exit button)^";
+              <Push exit_button>;
+              IncTime();
+              if (Stopped()) return true;
+              <<Go s_obj>>;
+          }
+          if (self in basement_landing && self hasnt open) {
+              if ( AmHolding(id_card) ) {
+                  print "(first inserting your ID card)^";
+                  <Insert (GetHeld(id_card)) id_slot>;
+                  IncTime();
+                  if (Stopped()) return true;
+                  <<Go n_obj>>;
+              }
+              else
+                  "You would need you ID card to do that.";
+          }
+        ],
+        react_before [; Go:
+            if (noun == n_to && self in basement_landing && self hasnt open)
+                <<Enter self>>;
+            if (noun == s_to && self in basement_corridor && self hasnt open)
+                <<Enter self>>;
+        ],
+        known_exterior_opening,
+        found_in basement_landing basement_corridor,
+  has   ;
+
+
+AutomaticDoor  upstairs_door "automatic door"
+  with  description [;
+          if (self in upstairs_landing) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_UPSTAIRS_CORRIDOR_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see a dim corridor. ";
+              if (IsIn(former_self,upstairs_corridor))
+                  print "In the shadows stands your past self. ";
+              print "On the right hand side is a slot for an ID card.^";
+          }
+          if (self in upstairs_corridor) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_UPSTAIRS_LANDING_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "plate glass sliding door, 
+                     through which you can see the upper part of the darkened foyer. ";
+              if (IsIn(former_self,upstairs_landing))
+                  print "In the shadows of the landing stands your past self. ";
+              print "On the right hand side is a green button.^";
+          }
+        ],
+        name 'door' 'automatic' 'auto' 'plate' 'glass' 'sliding',
+        when_closed [;
+          if (self in upstairs_landing)
+                    "On the north wall lies a closed automatic door.";
+          if (self in upstairs_corridor)
+                    "To the south is a closed automatic door, leading back
+                     to the landing.";
+        ],
+        when_open [;
+          if (self in upstairs_landing)
+                    "On the north wall lies an open automatic door.";
+          if (self in upstairs_corridor)
+                    "To the south is an open automatic door, leading back
+                     to the landing.";
+        ],
+        door_to [;
+          if (self in upstairs_landing)
+              return upstairs_corridor;
+          if (self in upstairs_corridor)
+              return upstairs_landing;
+        ],
+        door_dir [;
+          if (self in upstairs_landing)
+              return n_to;
+          if (self in upstairs_corridor)
+              return s_to;
+        ],
+        before [; 
+        Unlock:
+           if (IsOfType(second,crowbar))
+               <<Attack self>>;
+           else if (IsOfType(second,id_card) && (self in upstairs_landing))
+               <<Insert second id_slot>>;
+           else
+               "You cannot open the door with that.";
+        Open:
+          if (self in upstairs_landing)
+              if (AmHolding(id_card)) {
+                  print "(inserting your ID card)^";
+                  <<Insert (GetHeld(id_card)) id_slot>>;
+              }
+          if (self in upstairs_corridor) {
+              print "(pressing the green exit button)^";
+              <<Push exit_button>>;
+          }
+        Enter:
+          if (self in upstairs_corridor && self hasnt open) {
+              print "(first pressing the green exit button)^";
+              <Push exit_button>;
+              if (self has open) {
+                  IncTime();
+                  if (Stopped()) return true;
+                  <<Go s_obj>>;
+              }
+              return true;
+          }
+          if (self in upstairs_landing && self hasnt open) {
+              "There is no obvious way to get the automatic door to open.";
+          }
+        ],
+        react_before [; Go:
+            if (noun == s_to && self in upstairs_corridor && self hasnt open)
+                <<Enter self>>;
+        ],
+        found_in upstairs_landing upstairs_corridor,
+  has   ;
+
+Object  exit_button "green exit button"
+  with  description "A green button beside the door.",
+        name 'green' 'button',
+        before [; Push:
+            if (self in ground_corridor) {
+                ground_door.open_self(my_time+1);
+            }
+            if (self in upstairs_corridor) {
+                if (challenge)
+                    "Nothing happens -- the button must be broken.";
+                else
+                    upstairs_door.open_self(my_time+1);
+            }
+            if (self in basement_corridor) {
+                basement_door.open_self(my_time+1);
+            }
+            if (self in foyer) {
+                main_doors.open_self(my_time+1);
+            }
+            return true;
+          Receive:
+            "The button is set into a vertical surface, making it impossible
+             to place objects on top of it.";
+        ],
+       found_in ground_corridor upstairs_corridor basement_corridor foyer,
+  has  scenery concealed;
+
+Object  id_slot "ID card slot"
+  with  description "A narrow slot to the right of the door.
+                     The doors are coded so that only those with legitimate
+                     business can use their card to gain entrance.",
+
+        name 'slot',
+        found_in foyer upstairs_landing basement_landing,
+  has   scenery concealed;
+
+
+ManualDoor  ground_equipment_door "door to the equipment room"
+  with  name 'door' 'equipment' 'room' 'grey' 'gray' 'third' 'plain' 'ne' 'north-east',
+        description
+            "A simple gray door.",
+        door_to [;
+          if (self in ground_corridor)
+              return ground_equipment;
+          if (self in ground_equipment)
+              return ground_corridor;
+        ],
+        door_dir [;
+          if (self in ground_corridor)
+              return ne_to;
+          if (self in ground_equipment)
+              return w_to;
+        ],
+        before [;
+          Close:
+              if (((self in ground_equipment) && IsIn(former_self,ground_corridor)) ||
+                  ((self in ground_corridor) && IsIn(former_self,ground_equipment)) )  {
+                      CloseParadox();
+                      return true;
+              }
+          Open:
+              if (((self in ground_equipment) && IsIn(former_self,ground_corridor)) ||
+                  ((self in ground_corridor) && IsIn(former_self,ground_equipment)) )  {
+                      OpenParadox();
+                      return true;
+              }
+              else
+                  return (OpenManualDoor(self,second));
+          Unlock:
+              if (IsOfType(second,crowbar))
+                  <<Attack self>>;
+              if (((self in ground_equipment) && IsIn(former_self,ground_corridor)) ||
+                  ((self in ground_corridor) && IsIn(former_self,ground_equipment)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (UnlockManualDoor(self,second));
+          Lock:
+              if (((self in ground_equipment) && IsIn(former_self,ground_corridor)) ||
+                  ((self in ground_corridor) && IsIn(former_self,ground_equipment)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (LockManualDoor(self,second));
+        ],
+        with_key_type equipment_key,
+        found_in ground_corridor ground_equipment,
+  has   locked scenery;
+
+ManualDoor  basement_equipment_door "door to the equipment room"
+  with  name 'door' 'equipment' 'room' 'grey' 'gray' 'third' 'plain' 'ne' 'north-east',
+        description
+            "A simple gray door.",
+        door_to [;
+          if (self in basement_corridor)
+              return basement_equipment;
+          if (self in basement_equipment)
+              return basement_corridor;
+
+        ],
+        door_dir [;
+          if (self in basement_corridor)
+              return ne_to;
+          if (self in basement_equipment)
+              return w_to;
+        ],
+        before [;
+          Close:
+              if (((self in basement_equipment) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,basement_equipment)) )  {
+                      CloseParadox();
+                      return true;
+              }
+          Open:
+              if (((self in basement_equipment) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,basement_equipment)) )  {
+                      OpenParadox();
+                      return true;
+              }
+              else
+                  return (OpenManualDoor(self,second));
+          Unlock:
+              if (IsOfType(second,crowbar))
+                  <<Attack self>>;
+              if (((self in basement_equipment) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,basement_equipment)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (UnlockManualDoor(self,second));
+          Lock:
+              if (((self in basement_equipment) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,basement_equipment)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (LockManualDoor(self,second));
+        ],
+        with_key_type equipment_key,
+        found_in basement_corridor basement_equipment,
+  has   locked scenery;
+
+ManualDoor  deutsch_door "door to the Deutsch lab"
+  with  name 'door' 'deutsch' 'lab' 'fourth' 'north' 'n\\',
+        description [;
+          if (self in basement_corridor)
+              "A gray door with a small glass window,
+               looking into the darkened lab.";
+          if (self in deutsch_lab)
+              "A gray door with a small glass window,
+               looking into the darkened corridor.";
+        ],
+        door_to [;
+          if (self in basement_corridor)
+              return deutsch_lab;
+          if (self in deutsch_lab)
+              return basement_corridor;
+        ],
+        door_dir [;
+          if (self in basement_corridor)
+              return n_to;
+          if (self in deutsch_lab)
+              return s_to;
+        ],
+        before [;
+          Close:
+              if (((self in deutsch_lab) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,deutsch_lab)) )  {
+                      CloseParadox();
+                      return true;
+              }
+          Open:
+              if (((self in deutsch_lab) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,deutsch_lab)) )  {
+                      OpenParadox();
+                      return true;
+              }
+              else
+                  return (OpenManualDoor(self,second));
+          Unlock:
+              if (IsOfType(second,crowbar))
+                  <<Attack self>>;
+              if (((self in deutsch_lab) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,deutsch_lab)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (UnlockManualDoor(self,second));
+          Lock:
+              if (((self in deutsch_lab) && IsIn(former_self,basement_corridor)) ||
+                  ((self in basement_corridor) && IsIn(former_self,deutsch_lab)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (LockManualDoor(self,second));
+        ],
+        with_key_type deutsch_key,
+        found_in basement_corridor deutsch_lab,
+  has   locked scenery;
+
+ManualDoor  balcony_door "balcony door"
+  with  name 'door' 'balcony' 'n\\' 'north' 'glass',
+        description [;
+          if (self in upstairs_corridor) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_BALCONY_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "glass door looking out onto the balcony. ";
+              if (IsIn(former_self,balcony))
+                  print "In the shadows you can see your past self.^";
+              else
+                  print "^";
+          }
+          if (self in balcony) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_UPSTAIRS_CORRIDOR_);
+              print "A ";
+              if (self.smashed) print "cracked ";
+              print "glass door looking into the upstairs corridor. ";
+              if (IsIn(former_self,upstairs_corridor))
+                  print "In the shadows you can see your past self.^";
+              else
+                  print "^";
+          }
+        ],
+        when_closed [;
+          if (self in balcony)
+              "To the south, the door to the upstairs corridor stands closed.";
+          else
+             "At the north end of the corridor is a closed glass door leading out
+               to the balcony.";
+        ],
+        when_open [;
+          if (self in balcony)
+              "To the south, the door to the upstairs corridor lies open.";
+          else
+             "At the north end of the corridor is an open glass door leading out
+               to the balcony.";
+        ],
+        door_to [;
+          if (self in upstairs_corridor)
+              return balcony;
+          if (self in balcony)
+              return upstairs_corridor;
+
+        ],
+        door_dir [;
+          if (self in upstairs_corridor)
+              return n_to;
+          if (self in balcony)
+              return s_to;
+        ],
+        before [;
+          Close:
+              if (((self in balcony) && IsIn(former_self,upstairs_corridor)) ||
+                  ((self in upstairs_corridor) && IsIn(former_self,balcony)) )  {
+                      CloseParadox();
+                      return true;
+              }
+          Open:
+              if (((self in balcony) && IsIn(former_self,upstairs_corridor)) ||
+                  ((self in upstairs_corridor) && IsIn(former_self,balcony)) )  {
+                      OpenParadox();
+                      return true;
+              }
+              else
+                  return (OpenManualDoor(self,second));
+          Unlock:
+              if (IsOfType(second,crowbar))
+                  <<Attack self>>;
+              if (((self in balcony) && IsIn(former_self,upstairs_corridor)) ||
+                  ((self in upstairs_corridor) && IsIn(former_self,balcony)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (UnlockManualDoor(self,second));
+          Lock:
+              if (((self in balcony) && IsIn(former_self,upstairs_corridor)) ||
+                  ((self in upstairs_corridor) && IsIn(former_self,balcony)) )  {
+                      LockUnlockParadox();
+                      return true;
+              }
+              else
+                  return (LockManualDoor(self,second));
+          Attack:
+              if (AmHolding(crowbar)) {
+                  print "You swing the crowbar firmly into the door. It shudders,
+                         cracks reaching out from the point of impact, but the glass
+                         stays in place.^";
+                  self.smashed = true;
+                  StartSiren();
+                  return true;
+              }
+              else
+                "You don't have anything heavy enough to smash the door with.";              
+          Search:
+              <<Examine self>>;             
+        ],
+        smashed false,
+        with_key_type nothing,
+        found_in upstairs_corridor balcony,
+  has   ;
+
+Object  conference_window "window into the conference room"
+  with  name 'window' 'glass' 'tinted' 'remains' 'shards',
+        description [;
+          if (self in balcony) {
+              if (self has open)
+                  "The remains of a plate glass window that has been smashed in with
+                   something heavy. Large shards of glass still protrude from the edges,
+                   framing the murky interior of the conference room.";
+              else if (FlashLit())
+                  "My God! It's full of stars.";
+              else
+                  "A plate glass window looking into the murky interior of an conference room.";
+          }
+          if (self in conference_room) {
+              Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,X_BALCONY_);
+              if (self has open)
+                  print "The remains of a plate glass window that has been smashed in with
+                   something heavy. Large shards of glass still protrude from the edges,
+                   framing the starry night beyond. ";
+              else
+                  "A plate glass window looking out into the starry night. ";
+              if (IsIn(former_self,balcony))
+                  print "Against the stars, you can just make out the silhouette of your
+                         past self.^";
+              else
+                  print "^";
+          }
+        ],
+        when_closed [;
+          if (self in balcony)
+                    "To the south-east is a large, tinted glass window.";
+          if (self in conference_room)
+                    "To the north is a large plate glass window, amazingly intact.";
+
+        ],
+        when_open [;
+          if (self in balcony)
+                    "To the south-east, lie the shattered remains of a window, opening into
+                     a murky conference room.";
+
+          if (self in conference_room)
+                    "To the north, lie the shattered remains of a window, open to
+                     the starry night.";
+        ],
+        door_to [;
+          if (self in balcony)
+              return conference_room;
+          if (self in conference_room)
+              return balcony;
+
+        ],
+        door_dir [;
+          if (self in balcony)
+              return se_to;
+          if (self in conference_room)
+              return n_to;
+
+        ],
+        before [;
+          Open:
+              if (second == nothing)
+                  "The window appears to be locked from the inside.";
+          Unlock:
+              if (IsOfType(second, crowbar))
+                  <<Attack self>>;
+              else if (second ~= nothing)
+                  "You cannot get the window open with that.";
+              else
+                  "You cannot find the lock.";               
+          Attack:
+              if (AmHolding(crowbar)) {
+                  if (self has open)
+                      "The window is already thoroughly broken.";
+                  give self open;
+                  print "You swing the crowbar firmly into the window and it shatters with
+                   a loud crash.^";
+                  StartSiren();
+                  return true;
+              }
+              else
+                "You don't have anything heavy enough to smash the window with.";
+           Search:
+              <<Examine self>>;            
+        ],
+        with_key_type nothing,
+        found_in balcony conference_room,
+  has   static locked door lockable;
+
+
+
+!============================================================================
+!
+! Functions:
+!
+
+!----------------------------------------------------
+!
+! Entry point functions:
+
+
+! Puts the time in HH:MM:SS format on the status line
+
+[ DrawStatusLine width pos;
+
+ ! @split_window 0; 
+ ! return; 
+  
+  @split_window 1;
+  @set_window 1; 
+  @set_cursor 1 1; 
+  style reverse; 
+  width = 0->33; 
+  pos = width-20; 
+  spaces (width); 
+
+  @set_cursor 1 2; 
+  PrintShortName(location);
+   
+  @set_cursor 1 pos; 
+  print (PrintTime) my_time; 
+
+  @set_cursor 1 1; 
+  style roman; 
+  @set_window 0; 
+]; 
+
+[ ScoreSub;
+  if (deadflag == 0)
+    "There is no score in this game.";
+];
+
+[ ChooseObjects obj code;
+  if (code < 2) {
+      if (obj has scenery)
+          return 2;            ! exclude scenery from 'get all' commands
+      if (action_to_be == ##Take && obj has static)
+          return 2;            ! exclude scenery from 'get all' commands
+      rfalse;
+  }
+  if (action_to_be == ##Insert && obj in player)   ! prefer to insert into held objects
+      return 3;                                    ! particularly important with all
+                                                   ! these duplicates...
+  if (action_to_be == ##Close && (obj has openable) && (obj has open))
+      return 3;        
+  if (action_to_be == ##Open && (obj has openable) && (obj hasnt open))
+      return 3;        
+  if (action_to_be == ##Lock && (obj has lockable) && (obj hasnt locked))
+      return 3;        
+  if (action_to_be == ##Unlock && (obj has lockable) && (obj has locked))
+      return 3;        
+  if (action_to_be == ##LockSimple && (obj has lockable) && (obj hasnt locked))
+      return 3;        
+  if (action_to_be == ##UnlockSimple && (obj has lockable) && (obj has locked))
+      return 3;        
+  if (action_to_be == ##Take && obj has static)    ! prefer to get non-statics
+      return 1;
+  if (obj hasnt scenery)                           ! prefer non-scenery in general
+      return 2;
+  return 1; 
+]; 
+
+[ Initialise i;
+
+    lookmode = 2;            ! 'verbose'
+
+    my_time = start_time;
+       
+    location = foyer;
+
+    player = myselfobj;
+    
+    for (i=0 : i < MAX_ITEM_COPIES : i++) {
+               bomb-->i          = Bomb_.create();
+               id_card-->i       = IDCard_.create();
+               equipment_key-->i = EquipmentKey_.create();
+               deutsch_key-->i   = DeutschKey_.create();
+               flashlight-->i    = Flashlight_.create();
+               battery-->i       = Battery_.create();
+               cable-->i         = Cable_.create();
+               crowbar-->i       = Crowbar_.create();
+               notes-->i         = Notes_.create();
+    }
+
+    move bomb-->0          to player;
+    move id_card-->0       to player;
+    move deutsch_key-->0   to player;
+    move equipment_key-->0 to deutsch_lab;
+    move flashlight-->0    to deutsch_lab;
+    move battery-->0       to ground_equipment_gloom;
+    move cable-->0         to ground_equipment_gloom;
+    move crowbar-->0       to basement_equipment_gloom;
+    move notes-->0         to conference_table;
+
+    for (i=1 : i < MAX_ITEM_COPIES : i++) {
+               move bomb-->i          to limbo;
+               move id_card-->i       to limbo;
+               move equipment_key-->i to limbo;
+               move deutsch_key-->i   to limbo;
+               move flashlight-->i    to limbo;
+               move battery-->i       to limbo;
+               move cable-->i         to limbo;
+               move crowbar-->i       to limbo;
+               move notes-->i         to limbo;
+    }
+
+    for (i=0 : i < MAX_TIME_TRAVELS : i++) {
+               former_self-->i = FormerSelf_.create();
+               move former_self-->i to limbo;
+    }
+
+    InitHistory();
+
+    "^
+     ^
+     You're in.^
+     ^
+     The plan now is simple: go to your lab, plant the bomb, and run.
+     The prototype will be destroyed. The military will have no way to
+     continue the experiment. No-one will die.^
+     ^
+     The guard is out securing the grounds. The building is empty. You have six minutes.^
+     ^
+     ";
+
+];
+
+!----------------------------------------------------
+!
+! Major tasks:
+
+
+!! Initialises the first self's history for all items
+!!    First wipe's the history clean with all locations as 'limbo'
+!!    Next updates pre-start_time histories of all items and the player
+!!    Then updates the states with the proper pasts and UNKNOWN futures
+
+[InitHistory t i s;
+    for (t = EARLIEST_TIME : t <= FINAL_TIME : t++) {
+               for (i=0 : i < MAX_ITEM_COPIES : i++) {
+                       Put3D(bomb_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(id_card_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(equipment_key_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(deutsch_key_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(flashlight_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(battery_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(cable_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(crowbar_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+                       Put3D(notes_loc, 0, (t - EARLIEST_TIME),
+                                 i, limbo ); 
+
+            Put3D(flashlight_state, 0, (t - EARLIEST_TIME),
+                  i, UNKNOWN_ ); 
+            Put3D(bomb_setting, 0, (t - EARLIEST_TIME),
+                  i, UNKNOWN_ ); 
+               }
+    }
+
+    for (t = EARLIEST_TIME : t <= start_time : t++) {
+               Put3D(bomb_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(bomb-->0) ); 
+               Put3D(id_card_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(id_card-->0) ); 
+               Put3D(equipment_key_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(equipment_key-->0) ); 
+           Put3D(deutsch_key_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(deutsch_key-->0) ); 
+               Put3D(flashlight_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(flashlight-->0) ); 
+               Put3D(battery_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(battery-->0) ); 
+               Put3D(cable_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(cable-->0) ); 
+               Put3D(crowbar_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(crowbar-->0) ); 
+               Put3D(notes_loc, 0, (t - EARLIEST_TIME),
+                         0, parent(notes-->0) ); 
+       }
+    for (t = EARLIEST_TIME : t < start_time : t++) {   
+        Put2D(player_loc, 0, (t - EARLIEST_TIME), limbo); 
+    }
+       Put2D(player_loc, 0, start_time - EARLIEST_TIME, foyer); 
+
+    for (t = EARLIEST_TIME : t <= start_time : t++) {
+               for (s=0 : s < MAX_TIME_TRAVELS : s++) {
+                       Put2D(dangerous_activity, s, (t - EARLIEST_TIME),            NONE_);
+                       Put2D(activity_target, s, (t - EARLIEST_TIME),               nothing);
+                       Put2D(siren_state, s, (t - EARLIEST_TIME),                   false);
+                       Put2D(panel_setting, s, (t - EARLIEST_TIME),                 0);
+                       Put2D(basement_equipment_light, s, (t - EARLIEST_TIME),      false);
+                       Put2D(ground_equipment_light, s, (t - EARLIEST_TIME),        false);
+                       Put2D(main_doors_state, s, (t - EARLIEST_TIME),              LOCKED_);
+                       Put2D(basement_door_state, s, (t - EARLIEST_TIME),           LOCKED_);
+                       Put2D(ground_door_state, s, (t - EARLIEST_TIME),             LOCKED_);
+                       Put2D(upstairs_door_state, s, (t - EARLIEST_TIME),           LOCKED_);
+                       Put2D(balcony_door_state, s, (t - EARLIEST_TIME),            CLOSED_);
+                       Put2D(conference_window_state, s, (t - EARLIEST_TIME),       LOCKED_);
+                       Put2D(deutsch_door_state, s, (t - EARLIEST_TIME),            LOCKED_);
+                       Put2D(basement_equipment_door_state, s, (t - EARLIEST_TIME), LOCKED_);
+                       Put2D(ground_equipment_door_state, s, (t - EARLIEST_TIME),   LOCKED_);
+                       
+                       Put2D(main_doors_smashed, s, (t - EARLIEST_TIME),            false);
+                       Put2D(basement_door_smashed, s, (t - EARLIEST_TIME),         false);
+                       Put2D(ground_door_smashed, s, (t - EARLIEST_TIME),           false);
+                       Put2D(upstairs_door_smashed, s, (t - EARLIEST_TIME),         false);
+                       Put2D(balcony_door_smashed, s, (t - EARLIEST_TIME),          false);
+                       
+                       for (i=0 : i < MAX_ITEM_COPIES : i++) {    
+                Put3D(flashlight_state, 0, (t - EARLIEST_TIME),
+                      i, false ); 
+                Put3D(bomb_setting, 0, (t - EARLIEST_TIME),
+                      i, NA_ );
+                       }
+               }
+    }
+    
+    for (t = start_time+1 : t <= FINAL_TIME : t++) {
+               for (s=0 : s < MAX_TIME_TRAVELS : s++) {
+                       Put2D(dangerous_activity, s, (t - EARLIEST_TIME),            NONE_);
+                       Put2D(activity_target, s, (t - EARLIEST_TIME),               nothing);
+                       Put2D(siren_state, s, (t - EARLIEST_TIME),                   UNKNOWN_);
+                       Put2D(panel_setting, s, (t - EARLIEST_TIME),                 UNKNOWN_);
+                       Put2D(basement_equipment_light, s, (t - EARLIEST_TIME),      UNKNOWN_);
+                       Put2D(ground_equipment_light, s, (t - EARLIEST_TIME),        UNKNOWN_);
+                       Put2D(main_doors_state, s, (t - EARLIEST_TIME),              UNKNOWN_);
+                       Put2D(basement_door_state, s, (t - EARLIEST_TIME),           UNKNOWN_);
+                       Put2D(ground_door_state, s, (t - EARLIEST_TIME),             UNKNOWN_);
+                       Put2D(upstairs_door_state, s, (t - EARLIEST_TIME),           UNKNOWN_);
+                       Put2D(balcony_door_state, s, (t - EARLIEST_TIME),            UNKNOWN_);
+                       Put2D(conference_window_state, s, (t - EARLIEST_TIME),       UNKNOWN_);
+                       Put2D(deutsch_door_state, s, (t - EARLIEST_TIME),            UNKNOWN_);
+                       Put2D(basement_equipment_door_state, s, (t - EARLIEST_TIME), UNKNOWN_);
+                       Put2D(ground_equipment_door_state, s, (t - EARLIEST_TIME),   UNKNOWN_);
+
+                       Put2D(main_doors_smashed, s, (t - EARLIEST_TIME),            UNKNOWN_);
+                       Put2D(basement_door_smashed, s, (t - EARLIEST_TIME),         UNKNOWN_);
+                       Put2D(ground_door_smashed, s, (t - EARLIEST_TIME),           UNKNOWN_);
+                       Put2D(upstairs_door_smashed, s, (t - EARLIEST_TIME),         UNKNOWN_);
+                       Put2D(balcony_door_smashed, s, (t - EARLIEST_TIME),          UNKNOWN_);
+               }
+    }
+                         
+];
+
+!! Update the time, remove the old objects that don't travel,
+!! create new objects, move them to the appropriate places
+
+[TravelThroughTime time_amount t s i j;
+
+    last_travel_time = my_time;
+    
+    time_amount = time_amount / 5;   ! round down to nearest five seconds
+    if (time_amount == 0)
+        time_amount = 1;
+        
+    my_time = my_time - time_amount;
+
+    if (my_time < early_guard_time) {
+        d_paradox = true;
+        deadflag = 3;
+        Seperator();
+        print (Nearby) 0, "the guard gives the inside corridors a last look before
+                           heading out. A small sound from the Deutsch lab. He turns.^"; 
+        print "^Time unravels...^";
+        Devours(my_time); 
+        return true;                           
+    }
+          
+    !! replace those items the player brought with them
+    
+    FixBombSettings(time_amount);
+    FixFlashlightStates();
+        
+    for (j=0 : j < Exp(2,time_travelled) : j++) {
+        ReplaceTravellingItem(bomb, j);
+        ReplaceTravellingItem(id_card, j);
+        ReplaceTravellingItem(equipment_key, j);
+        ReplaceTravellingItem(deutsch_key, j);
+        ReplaceTravellingItem(flashlight, j);
+
+        ReplaceTravellingItem(cable, j);
+        ReplaceTravellingItem(crowbar, j);
+        ReplaceTravellingItem(notes, j);
+        
+        !! tricky battery issues, since they can be in flashlights
+        !! if other items could be in containers this would hurt here too
+        
+        if (PlayerHas(battery-->j)) {
+            if (battery-->j in player)
+                move battery-->(j+Exp(2,time_travelled)) to player;
+            else {
+                for (i=0 : i < Exp(2,time_travelled) : i++)
+                    if (battery-->j in (flashlight-->i))
+                        move (battery-->(j+Exp(2,time_travelled))) to (flashlight-->(i+Exp(2,time_travelled)));
+            }
+        }
+        else if (LocationOf(battery-->j) == prototype_interior) {
+            if (battery-->j in prototype_interior)
+                move battery-->(j+Exp(2,time_travelled)) to prototype_interior;
+            else
+                for (i=0 : i < Exp(2,time_travelled) : i++)
+                    if (battery-->j in flashlight-->i)
+                        move battery-->(j+Exp(2,time_travelled)) to
+                             flashlight-->(i+Exp(2,time_travelled));
+        }
+
+    }
+
+    
+    !! move all the old items and selves into limbo
+    
+    for (t=0 : t < Exp(2,time_travelled) : t++) {
+               move bomb-->t          to limbo;
+               move id_card-->t       to limbo;
+               move equipment_key-->t to limbo;
+               move deutsch_key-->t   to limbo;
+               move flashlight-->t    to limbo;
+               move battery-->t       to limbo;
+               move cable-->t         to limbo;
+               move crowbar-->t       to limbo;
+               move notes-->t         to limbo;
+    }
+     
+    for (t=0 : t < time_travelled : t++)
+        move former_self-->t   to limbo;
+    
+
+    !! fix up history of immediate past self so 'player' becomes appropriate former self
+    
+    for (s = EARLIEST_TIME : s <= FINAL_TIME : s++) {
+        for (t=0 : t < Exp(2,time_travelled) : t++) {
+            if (Get3D(bomb_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(bomb_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(id_card_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(id_card_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(equipment_key_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(equipment_key_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(deutsch_key_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(deutsch_key_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(flashlight_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(flashlight_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(battery_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(battery_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(cable_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(cable_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(crowbar_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(crowbar_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+            if (Get3D(notes_loc, time_travelled, (s - EARLIEST_TIME), t) == player)
+                Put3D(notes_loc, time_travelled, (s - EARLIEST_TIME), t,
+                      former_self-->time_travelled);
+        }
+    }
+
+    !! recreate the world as it was for most recent former self
+    !! (ie move a lot of old items and selves back to the world)
+    !! (fix states of doors and machine)
+    
+    for (i=0 : i < Exp(2,time_travelled) : i++) {
+               move bomb-->i          to Get3D(bomb_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move id_card-->i       to Get3D(id_card_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move equipment_key-->i to Get3D(equipment_key_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move deutsch_key-->i   to Get3D(deutsch_key_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move flashlight-->i    to Get3D(flashlight_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move battery-->i       to Get3D(battery_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move cable-->i         to Get3D(cable_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move crowbar-->i       to Get3D(crowbar_loc,time_travelled,my_time-EARLIEST_TIME,i);
+               move notes-->i         to Get3D(notes_loc,time_travelled,my_time-EARLIEST_TIME,i);
+    }
+    for (t=0 : t <= time_travelled : t++) {
+        if (Get2D(player_loc,t,my_time-EARLIEST_TIME) == nothing)
+            move former_self-->t to limbo;
+        else
+            move former_self-->t to Get2D(player_loc,t,my_time-EARLIEST_TIME);
+    }
+    
+    if (my_time < prototype_fixed_time)
+        prototype.fixed = false;
+    
+    SetBombs();
+    SetFlashlights();
+    SetPanel(panel_setting);
+    SetBasementLight(basement_equipment_light);
+    SetGroundLight(ground_equipment_light);
+    SetAutomaticDoor(main_doors, main_doors_state);
+    SetAutomaticDoor(basement_door, basement_door_state);
+    SetAutomaticDoor(ground_door, ground_door_state);
+    SetAutomaticDoor(upstairs_door, upstairs_door_state);
+    SetManualDoor(balcony_door, balcony_door_state); 
+    SetManualDoor(conference_window, conference_window_state); 
+    SetManualDoor(deutsch_door, deutsch_door_state); 
+    SetManualDoor(basement_equipment_door, basement_equipment_door_state); 
+    SetManualDoor(ground_equipment_door, ground_equipment_door_state); 
+
+    SetBrokenDoor(main_doors, main_doors_smashed);
+    SetBrokenDoor(basement_door, basement_door_smashed);
+    SetBrokenDoor(ground_door, ground_door_smashed);
+    SetBrokenDoor(upstairs_door, upstairs_door_smashed);
+    SetBrokenDoor(balcony_door, balcony_door_smashed); 
+                       
+    !! initialise the history for the new self from the most recent self
+                
+    for (t = EARLIEST_TIME : t <= FINAL_TIME : t++) {
+               for (i=0 : i < MAX_ITEM_COPIES : i++) {
+                       Put3D(bomb_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(bomb_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(id_card_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(id_card_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(equipment_key_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(equipment_key_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(deutsch_key_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(deutsch_key_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(flashlight_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(flashlight_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(battery_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(battery_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(cable_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(cable_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(crowbar_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(crowbar_loc, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(notes_loc, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(notes_loc, time_travelled, (t - EARLIEST_TIME), i));
+
+                       Put3D(bomb_setting, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(bomb_setting, time_travelled, (t - EARLIEST_TIME), i));
+                       Put3D(flashlight_state, time_travelled+1, (t - EARLIEST_TIME), i,
+                             Get3D(flashlight_state, time_travelled, (t - EARLIEST_TIME), i));
+               }
+               Put2D(dangerous_activity, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(dangerous_activity, time_travelled, (t - EARLIEST_TIME)));            
+               Put2D(activity_target, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(activity_target, time_travelled, (t - EARLIEST_TIME)));               
+               Put2D(siren_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(siren_state, time_travelled, (t - EARLIEST_TIME)));           
+               Put2D(panel_setting, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(panel_setting, time_travelled, (t - EARLIEST_TIME)));         
+               Put2D(basement_equipment_light, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(basement_equipment_light, time_travelled, (t - EARLIEST_TIME)));              
+               Put2D(ground_equipment_light, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(ground_equipment_light, time_travelled, (t - EARLIEST_TIME)));                
+               Put2D(main_doors_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(main_doors_state, time_travelled, (t - EARLIEST_TIME)));
+               Put2D(basement_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(basement_door_state, time_travelled, (t - EARLIEST_TIME)));           
+               Put2D(ground_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(ground_door_state, time_travelled, (t - EARLIEST_TIME)));             
+               Put2D(upstairs_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(upstairs_door_state, time_travelled, (t - EARLIEST_TIME)));           
+               Put2D(balcony_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(balcony_door_state, time_travelled, (t - EARLIEST_TIME)));            
+               Put2D(conference_window_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(conference_window_state, time_travelled, (t - EARLIEST_TIME)));               
+               Put2D(deutsch_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(deutsch_door_state, time_travelled, (t - EARLIEST_TIME)));            
+               Put2D(basement_equipment_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(basement_equipment_door_state, time_travelled, (t - EARLIEST_TIME)));         
+               Put2D(ground_equipment_door_state, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(ground_equipment_door_state, time_travelled, (t - EARLIEST_TIME)));           
+
+               Put2D(main_doors_smashed, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(main_doors_smashed, time_travelled, (t - EARLIEST_TIME)));
+               Put2D(basement_door_smashed, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(basement_door_smashed, time_travelled, (t - EARLIEST_TIME)));         
+               Put2D(ground_door_smashed, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(ground_door_smashed, time_travelled, (t - EARLIEST_TIME)));           
+               Put2D(upstairs_door_smashed, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(upstairs_door_smashed, time_travelled, (t - EARLIEST_TIME)));         
+               Put2D(balcony_door_smashed, time_travelled+1, (t - EARLIEST_TIME),
+                   Get2D(balcony_door_smashed, time_travelled, (t - EARLIEST_TIME)));          
+       }
+
+    time_travelled++;
+    
+    return true;
+];
+
+[ReplaceTravellingItem thing_type i;
+   if (PlayerHas(thing_type-->i))
+       move thing_type-->(i+Exp(2,time_travelled)) to player;
+   else if (LocationOf(thing_type-->i) == prototype_interior)
+       move thing_type-->(i+Exp(2,time_travelled)) to prototype_interior;
+];
+
+
+[FixBombSettings time_amount i;
+    for (i=0 : i < Exp(2,time_travelled) : i++) {
+       if (PlayerHas(bomb-->i) || (LocationOf(bomb-->i) == prototype_interior))
+           if ((bomb-->i).time_value ~= NA_)
+               (bomb-->(i+Exp(2,time_travelled))).time_value 
+                                 = (bomb-->i).time_value - time_amount;
+       (bomb-->i).time_value = NA_;
+    }
+];
+
+[FixFlashlightStates i;
+    for (i=0 : i < Exp(2,time_travelled) : i++) {
+       if (PlayerHas(flashlight-->i) || (LocationOf(flashlight-->i) == prototype_interior)) {
+           if (flashlight-->i has on)
+               give flashlight-->(i+Exp(2,time_travelled)) on;
+           else
+               give flashlight-->(i+Exp(2,time_travelled)) ~on;       
+       }
+       give flashlight-->i ~on;
+    }
+];
+
+
+!----------------------------------------------------
+!
+! Little utility functions:
+
+
+[IsOfType thing thing_type i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (thing_type-->i == thing)
+            return true;
+    return false;
+]; 
+
+[AmHolding thing_type i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (thing_type-->i ~= nothing && thing_type-->i in player)
+            return true;
+    return false;
+]; 
+
+[GetHeld thing_type i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (thing_type-->i ~= nothing && thing_type-->i in player)
+            return thing_type-->i;
+    return false;
+]; 
+
+[IsIn thing_type loc i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (thing_type-->i ~= nothing && thing_type-->i in loc)
+            return true;
+    return false;
+]; 
+
+[GetFrom thing_type loc i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (thing_type-->i ~= nothing && thing_type-->i in loc)
+            return thing_type-->i;
+    return false;
+]; 
+
+![Present thing_type t;
+!    for (t=0 : t < MAX_ITEM_COPIES : t++)
+!        if (thing_type-->t ~= nothing && thing_type-->t in real_location)
+!            return true;
+!    return false;
+!]; 
+
+![GetPresent thing_type t;
+!    for (t=0 : t < MAX_ITEM_COPIES : t++)
+!        if (thing_type-->t ~= nothing && thing_type-->t in real_location)
+!            return thing_type-->t;
+!    return false;
+!]; 
+
+[BatteriesContained thing batteries i;
+    batteries = 0;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (battery-->i ~= nothing && battery-->i in thing)
+            batteries++;
+    return batteries;
+]; 
+
+[StartSiren;
+    if (siren_start_time == UNKNOWN_ || siren_start_time > my_time)
+      siren_start_time = my_time;
+];
+
+[MoveMoveableChildren old_loc new_loc x y;
+    while (child(old_loc)) {
+        x = nothing;
+        y = child(old_loc);
+        if ((y hasnt static) && (y ~= player)) {
+            x = y;
+        }
+        while (sibling(y)) {
+            y = sibling(y);
+            if ((y hasnt static) && (y ~= player)) {
+                x = y;
+            }
+        }
+        if (x ~= nothing) {
+            move x to new_loc;
+        }
+        else
+            break;
+    }
+];
+
+[ LocationOf x;
+    if (parent(x) == 0)
+        return x;
+    else
+        return LocationOf(parent(x));
+];
+
+[ PlayerHas x;
+    if (parent(x) == 0)
+        return false;
+    if (parent(x) == player)
+        return true;
+    return PlayerHas(parent(x));
+];
+
+[ Flashlit i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++) {
+        if (flashlight-->i ~= nothing && (flashlight-->i in player or real_location)
+            && flashlight-->i has on)
+            return true;
+     }
+     return false;
+];
+
+[PrintTime t;
+    if (t == NA_)
+        return true;
+
+    print (t/720), ":", ((t/12)%60)/10, (t/12)%10, ":", ((t%12)/2);
+    if ((t%2) == 0)
+       print "0";
+    else
+       print "5"; 
+
+    if (t/(720*12) == 0)
+        print " am";
+    else
+        print " pm";
+];
+
+[PrintShortTime t;
+    print (t/720), ":", ((t/12)%60)/10, (t/12)%10;
+
+    if (t/(720*12) == 0)
+        print " am";
+    else
+        print " pm";
+];
+
+[IncTime;
+    InformLibrary.end_turn_sequence();
+];
+
+!! x == run_through, y == time_index
+
+[Put2D array x y thing;
+    array-->((x * (GAME_LENGTH+1)) + y) = thing;
+];
+
+!! x == run_through, y == time_index
+
+[Get2D array x y;
+    return array-->((x * (GAME_LENGTH+1)) + y);
+];
+
+!! x == run_through, y == time_index, z == thing_number
+
+[Put3D array x y z thing;
+    array-->( (z*(MAX_TIME_TRAVELS+1) + x)*(GAME_LENGTH+1) + y ) = thing;
+];
+
+!! x == run_through, y == time_index, z == thing_number
+
+[Get3D array x y z;
+    return array-->( (z*(MAX_TIME_TRAVELS+1) + x)*(GAME_LENGTH+1) + y );
+];
+
+[Exp b e i result;
+    result = 1;
+    for (i=0 : i<e : i++)
+        result = result * b;
+    return result;
+];
+
+!----------------------------------------------------
+!
+! 'Observe' functions:    (these make note of current state of things)
+
+
+[ObserveBombs i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++) {
+        Put3D(bomb_setting, time_travelled, (my_time - EARLIEST_TIME), i, (bomb-->i).time_value); 
+    }
+];
+
+[ObserveFlashlights i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++) {
+        Put3D(flashlight_state, time_travelled, (my_time - EARLIEST_TIME), i, flashlight-->i has on); 
+    }
+];
+
+[ObserveSiren siren_on;
+    siren_on = (siren_start_time ~= UNKNOWN_) && (siren_start_time < my_time);
+    Put2D(siren_state, time_travelled, my_time - EARLIEST_TIME, siren_on);
+];
+
+[ObservePanel;
+    Put2D(panel_setting, time_travelled, my_time - EARLIEST_TIME, control_panel.time_value);
+];
+
+[ObserveGroundLight light_array;
+    Put2D(light_array, time_travelled, my_time - EARLIEST_TIME, ground_equipment.lit);
+];
+
+[ObserveBasementLight light_array;
+    Put2D(light_array, time_travelled, my_time - EARLIEST_TIME, basement_light_switch.blown);
+];
+
+[ObserveBrokenDoor door door_smashed;
+    Put2D(door_smashed, time_travelled, my_time - EARLIEST_TIME, door.smashed);
+];
+
+[ObserveManualDoor door door_state door_status;
+    if (door has locked)
+        door_status = LOCKED_;
+    else {
+        if (door has open)
+            door_status = OPEN_;
+        else
+            door_status = CLOSED_;
+    }
+    Put2D(door_state, time_travelled, my_time - EARLIEST_TIME, door_status);
+];
+
+[ObserveAutomaticDoor door door_state door_status;
+    if (door has locked)
+        door_status = 0;
+    else
+        door_status = door.to_close_at;
+    Put2D(door_state, time_travelled, my_time - EARLIEST_TIME, door_status);
+];
+
+[ObserveLocations i;
+    Put2D(player_loc, time_travelled, (my_time - EARLIEST_TIME), parent(player)); 
+    for (i=0 : i < MAX_ITEM_COPIES : i++) {
+        Put3D(bomb_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(bomb-->i) ); 
+        Put3D(id_card_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(id_card-->i) ); 
+        Put3D(equipment_key_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(equipment_key-->i) ); 
+        Put3D(deutsch_key_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(deutsch_key-->i) ); 
+        Put3D(flashlight_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(flashlight-->i) ); 
+        Put3D(battery_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(battery-->i) ); 
+        Put3D(cable_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(cable-->i) ); 
+        Put3D(crowbar_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(crowbar-->i) ); 
+        Put3D(notes_loc, time_travelled, (my_time - EARLIEST_TIME),
+              i, parent(notes-->i) ); 
+    }
+];
+
+!----------------------------------------------------
+!
+! 'Set' functions:    (these take care of certain former actions every turn)
+
+
+[SetBombs setting_now i;
+    for (i=0 : i < Exp(2,time_travelled) : i++) {
+        setting_now  = Get3D(bomb_setting,time_travelled,my_time-EARLIEST_TIME,i);
+        (bomb-->i).time_value = setting_now;
+    }
+];
+
+[SetFlashlights setting_now i;
+    for (i=0 : i < Exp(2,time_travelled) : i++) {
+        setting_now  = Get3D(flashlight_state,time_travelled,my_time-EARLIEST_TIME,i);
+        if (setting_now == true)
+            give flashlight-->i on;
+        else
+            give flashlight-->i ~on;
+    }
+];
+
+[SetPanel setting_array setting_now;
+    setting_now = Get2D(setting_array, time_travelled, my_time - EARLIEST_TIME);    
+    control_panel.time_value = setting_now;
+];
+
+[SetBasementLight setting_array setting_now;
+    setting_now = Get2D(setting_array, time_travelled, my_time - EARLIEST_TIME);    
+    basement_light_switch.blown = setting_now;
+];
+
+[SetGroundLight setting_array setting_now;
+    setting_now = Get2D(setting_array, time_travelled, my_time - EARLIEST_TIME);    
+    ground_equipment.lit = setting_now;
+    if (setting_now)
+        give ground_light_switch on;
+    else
+        give ground_light_switch ~on;
+];
+
+[SetManualDoor door door_state door_status;
+    door_status = Get2D(door_state, time_travelled, my_time - EARLIEST_TIME);    
+    if (door_status == LOCKED_) {
+        give door ~open;
+        give door locked;
+    }
+    if (door_status == CLOSED_) {
+        give door ~open;
+        give door ~locked;
+    }
+    if (door_status == OPEN_) {
+        give door open;
+        give door ~locked;
+    }
+    if (door_status == UNKNOWN_) {
+        print "Error: unknown door status needing to be set for some reason.";
+    }
+];
+
+[SetAutomaticDoor door door_state door_status;
+    door_status = Get2D(door_state, time_travelled, my_time - EARLIEST_TIME);
+    if (door_status == UNKNOWN_) {
+        give door ~open locked;
+    }
+    if (door_status > 0) {
+        give door open ~locked;
+        door.to_close_at = door_status;
+    }
+];
+
+[SetBrokenDoor door door_smashed door_status;
+    door_status = Get2D(door_smashed, time_travelled, my_time - EARLIEST_TIME);
+    if (door_status == UNKNOWN_) {
+        door.smashed = false;
+    }
+    if (door_status == true) {
+        door.smashed = true;
+    }
+    if (door_status == false) {
+        door.smashed = false;
+    }
+];
+
+[MoveFormerSelf run_through loc_next;
+    loc_next = Get2D(player_loc, run_through, my_time - EARLIEST_TIME);
+
+    if (~~d_paradox) {
+        if (d_destroyed_prototype && ((former_self-->run_through) in limbo) &&
+            (loc_next == prototype_interior))    {
+                        d_paradox = true;
+                        deadflag = 3;
+                        Seperator();
+                        print (PrintTime) (my_time), "^^";
+                        print "Back in the Deutsch lab, the debris from the prototype
+                               lies smoldering on the floor and no past self appears.^"; 
+                        print "^Time unravels...^";
+                        Devours(my_time);                            
+        }   
+        else if (d_destroyed_prototype && (my_time == start_time))    {
+                        d_paradox = true;
+                        deadflag = 3;
+                        Seperator();
+                        print (PrintTime) (my_time), "^^";
+                        print "Elsewhere, your past self enters the foyer and smells the
+                               bitter smoke from a recent explosion.^"; 
+                        print "^Time unravels...^";
+                        Devours(my_time);                            
+        }   
+        else {
+            if (loc_next == nothing)
+                move former_self-->run_through to limbo;
+            else
+                move former_self-->run_through to loc_next;    
+        }
+        
+!        if ((~~d_paradox) && (~~d_escaped) && (~~d_caught))
+!            print "<<< former self (", run_through, ") is in: ", (name) loc_next, " >>>^";
+    }
+];
+
+!! Moves an object around according to the actions of former selves
+!! Uses the item histories to work out when an item was moved, but since
+!! that copy of the item may have been swapped for another (which is fine)
+!! we must get the first available copy in the right location to be safe.
+!! Also, we don't want to remove all normal objects when someone time-travels
+!! so, since this only happens when the player is not present and no other moving
+!! happens when the player is not present, we can get around it by only moving
+!! objects when a former self is present in the same location.
+
+[MoveObject thing_type thing_loc i loc_now loc_next;
+    loc_now  = Get3D(thing_loc,time_travelled-1,my_time-EARLIEST_TIME-1,i);
+    loc_next = Get3D(thing_loc,time_travelled-1,my_time-EARLIEST_TIME,i);
+    if (loc_now ~= loc_next) {
+        if (IsIn(thing_type, loc_now)) {
+            if (IsIn(former_self,LocationOf(GetFrom(thing_type, loc_now)))) {
+!                print "<<< Moving ", (name) thing_type-->i, " (", i, ") in ", (name) loc_now, 
+!                      " to ", (name) loc_next, " >>>^";
+                move GetFrom(thing_type, loc_now) to loc_next;
+             }
+             else {
+                !! handle the odd case of object left in prototype when button pressed
+                if (LocationOf(GetFrom(thing_type, loc_now)) == prototype_interior) {
+!                    print "<<< Moving ", (name) thing_type-->i, " (", i, ") in ", (name) loc_now, 
+!                          " to ", (name) loc_next, " >>>^";
+                    move GetFrom(thing_type, loc_now) to loc_next;                    
+                }
+                else if ((loc_now == basement_equipment_gloom) || (loc_now == ground_equipment_gloom)) {
+!                    print "<<< Moving ", (name) thing_type-->i, " (", i, ") in ", (name) loc_now, 
+!                          " to ", (name) loc_next, " >>>^";
+                    move GetFrom(thing_type, loc_now) to loc_next;                                    
+                }
+!                else {
+!                    print "<<< Ignoring ", (name) thing_type-->0, " in ", (name) loc_now, 
+!                          " (wanted to move it to ", (name) loc_next, ") >>>^";             
+!                }
+             }
+        }
+!        else
+!            print "<<< Missing ", (name) thing_type-->0, " in ", (name) loc_now, 
+!                  " (wanted to move it to ", (name) loc_next, ") >>>^";
+    }
+];
+
+!----------------------------------------------------
+!
+! 'Maybe' functions:   (these take care of former actions)
+
+
+[MaybeExplodeBombs i;
+    for (i=0 : i < MAX_ITEM_COPIES : i++)
+        if (bomb-->i ~= nothing) {
+            if (LocationOf(bomb-->i) ~= limbo) {
+                if (((bomb-->i).time_value == my_time - 1) &&
+                    ((bomb-->i).left_over_seconds == 0))
+                        ExplodeBomb(i);
+                else if (((bomb-->i).time_value == my_time - 2) &&
+                         ((bomb-->i).left_over_seconds ~=0))
+                    ExplodeBomb(i);
+            }
+        }
+];
+  
+[MaybeSing;
+       if (Get2D(dangerous_activity, time_travelled-1, my_time-EARLIEST_TIME-1) == SING_)
+           if (player notin limbo)
+               "You hear muffled singing from somewhere in the building.";
+];
+
+[MaybeShout;
+       if (Get2D(dangerous_activity, time_travelled-1, my_time-EARLIEST_TIME-1) == SHOUT_)
+           if (player notin limbo)
+               "You hear muffled shouting from somewhere in the building.";
+];
+              
+!!! a little tricky to ensure that when two bombs are in same room that the one set
+!!! has the same original setting as it should (ie is indistinguishable from former one)
+
+[MaybeSetBombs setting_now setting_next loc_now b i j;
+    for (i=0 : i < Exp(2,time_travelled-1) : i++) {
+        setting_now  = Get3D(bomb_setting,time_travelled-1,my_time-EARLIEST_TIME-1,i);
+        setting_next = Get3D(bomb_setting,time_travelled-1,my_time-EARLIEST_TIME,i);
+        loc_now  = Get3D(bomb_loc,time_travelled-1,my_time-EARLIEST_TIME-1,i);
+        if (setting_now ~= setting_next) {
+            if (IsIn(bomb, loc_now)) {
+                if (IsIn(former_self,LocationOf(GetFrom(bomb, loc_now)))) {
+                    for (j=0 : j < MAX_ITEM_COPIES : j++)
+                        if ((bomb-->j ~= nothing) && (bomb-->j in loc_now))
+                            if ((bomb-->j).time_value == setting_now)
+                                b = bomb-->j;
+!                    print "<<< setting bomb (via maybeset) >>>^";
+                    if (b ~= nothing)
+                        b.time_value = setting_next;
+!                    else
+!                       print "<<<Missing bomb of former time setting.>>>^";
+                }
+            }
+!            else
+!                print "<<<Missing ", (name) bomb-->0, " in ", (name) loc_now, 
+!                      " (wanted to set it to ", setting_next, ")>>>^";
+        }
+    }
+];
+
+!!! a little tricky to ensure that when two flashlights are in same room that the one set
+!!! has the same original setting as it should (ie is indistinguishable from former one)
+
+[MaybeSetFlashlights setting_now setting_next loc_now f i j;
+    for (i=0 : i < Exp(2,time_travelled-1) : i++) {
+        setting_now  = Get3D(flashlight_state,time_travelled-1,my_time-EARLIEST_TIME-1,i);
+        setting_next = Get3D(flashlight_state,time_travelled-1,my_time-EARLIEST_TIME,i);
+        loc_now  = Get3D(flashlight_loc,time_travelled-1,my_time-EARLIEST_TIME-1,i);
+        if (setting_now ~= setting_next) {
+            if (IsIn(flashlight, loc_now)) {
+                if (IsIn(former_self,LocationOf(GetFrom(flashlight, loc_now)))) {
+                    for (j=0 : j < MAX_ITEM_COPIES : j++)
+                        if ((flashlight-->j ~= nothing) && (flashlight-->j in loc_now))
+                            if ((flashlight-->j has on) == setting_now)
+                                f = flashlight-->j;
+!                    print "<<< setting flashlight (via maybeset) >>>^";
+                    if (f ~= nothing) {
+                        if (setting_next == true)
+                            give f on;
+                        else
+                            give f ~on;
+                    }
+!                    else
+!                       print "<<<Missing flashlight of former time setting.>>>^";
+                }
+            }
+!            else
+!                print "<<<Missing ", (name) flashlight-->0, " in ", (name) loc_now, 
+!                      " (wanted to set it to ", setting_next, ")>>>^";
+        }
+    }
+];
+
+[MaybeSetPanel setting_array setting_now setting_next;
+    setting_now = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME - 1);
+    setting_next = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME);
+    if (setting_next ~= UNKNOWN_ && setting_next ~= setting_now) { 
+        control_panel.time_value = setting_next;
+    }
+];
+
+[MaybeSetBasementLight setting_array setting_now setting_next;
+    setting_now = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME - 1);
+    setting_next = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME);
+    if (setting_next ~= UNKNOWN_ && setting_next ~= setting_now) { 
+        basement_light_switch.blown = setting_next;
+    }
+];
+
+[MaybeSetGroundLight setting_array setting_now setting_next;
+    setting_now = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME - 1);
+    setting_next = Get2D(setting_array, time_travelled - 1, my_time - EARLIEST_TIME);
+    if (setting_next ~= UNKNOWN_ && setting_next ~= setting_now) { 
+        ground_equipment.lit = setting_next;
+        if (setting_next)
+            give ground_light_switch on;
+        else
+            give ground_light_switch ~on;
+    }
+];
+
+[MaybeCloseAutomaticDoor door;
+    if (door.just_closed)
+        door.just_closed = false;
+    if (~~deadflag)
+        if (door.to_close_at == my_time - 1)
+            door.close_self();
+];
+
+!! Opens/closes/locks/unlocks doors for the past self and catches paradoxes that could not
+!! be seen, but where the locked/unlocked state of the door differs and interferes with the action.
+!! Also works when the former self unlocks an unlocked door or locks
+!! a locked door, but this door had the converse state and the key actually turns.
+
+[MaybeSetManualDoor door door_state past_door_status_now past_door_status_next
+                    present_door_status_now the_action t;
+    
+    for (t=0 : t<time_travelled : t++) {
+
+        past_door_status_now = Get2D(door_state, t, my_time - EARLIEST_TIME - 1);
+        past_door_status_next = Get2D(door_state, t, my_time - EARLIEST_TIME);
+
+        present_door_status_now = Get2D(door_state, time_travelled, my_time - EARLIEST_TIME - 1);
+        
+        the_action = Get2D(dangerous_activity, t, my_time - EARLIEST_TIME - 1);
+
+!-- if there was a locking/unlocking, check for paradox:
+        if (Get2D(activity_target, t, my_time - EARLIEST_TIME - 1) == door) {
+            if (the_action == UNLOCK_) {
+                if ((present_door_status_now == CLOSED_) && (past_door_status_now == LOCKED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self attempts to unlock ", (the) door,
+                                      " but finds it already unlocked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+                else if ((present_door_status_now == LOCKED_) && (past_door_status_now == CLOSED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self foolishly attempts to unlock ", (the) door,
+                                      " and succeeds where you had originally found it already unlocked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+            }
+            if (the_action == LOCK_) {
+                if ((present_door_status_now == CLOSED_) && (past_door_status_now == LOCKED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self foolishly attempts to lock ", (the) door,
+                                      " and succeeds where you had originally found it already locked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+                if ((present_door_status_now == LOCKED_) && (past_door_status_now == CLOSED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self attempts to lock ", (the) door,
+                                      " but finds it already locked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+            }
+            if (the_action == OPEN_) {
+                if ((present_door_status_now == CLOSED_) && (past_door_status_now == LOCKED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self foolishly attempts to open ", (the) door,
+                                      " and succeeds where you had originally found it locked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+                if ((present_door_status_now == LOCKED_) && (past_door_status_now == CLOSED_)) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                                print (Nearby) 0, "your past self attempts to open ", (the) door,
+                                      " but finds it locked.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+            }
+        }
+        
+!-- if there should be a state change, do it:
+        if (~~d_paradox) {
+            if ((past_door_status_now ~= past_door_status_next) && (past_door_status_next ~= UNKNOWN_)) {             
+                if (past_door_status_now == present_door_status_now) {
+                    if (past_door_status_next == LOCKED_) {
+                        give door ~open;
+                        give door locked;
+                        if (door in real_location)
+                            print "You hear someone locking the ", (name) door, ".^";
+                    }
+                    if (past_door_status_next == CLOSED_) {
+                        give door ~open;
+                        give door ~locked;
+                        if (door in real_location && past_door_status_now == LOCKED_)
+                            print "You hear someone unlocking the ", (name) door, ".^";
+                        if (door in real_location && past_door_status_now == OPEN_)
+                            print "Someone closes ", (name) door, ".^";
+                    }
+                    if (past_door_status_next == OPEN_) {
+                        give door open;
+                        give door ~locked;
+                        if (door in real_location)
+                            print "Someone opens the ", (name) door, ".^";
+                    }
+                }
+            }
+        }
+        
+    }
+];
+
+[MaybeSetAutomaticDoor door door_state door_status_now door_status_next;
+    door_status_now = Get2D(door_state, time_travelled - 1, my_time - EARLIEST_TIME - 1);
+    door_status_next = Get2D(door_state, time_travelled - 1, my_time - EARLIEST_TIME);
+    if (door_status_next == my_time) {
+        door.open_self(my_time);
+    }
+    if ((door == main_doors) && (my_time == start_time - 1)) {
+        door.open_self(my_time);
+    }
+];
+
+[MaybeBreakDoor door door_smashed door_smashed_next;
+    door_smashed_next = Get2D(door_smashed, time_travelled - 1, my_time - EARLIEST_TIME);
+    if (door_smashed_next && (~~door.smashed)) {
+        door.smashed = true;
+    }
+];
+
+!----------------------------------------------------
+!
+! 'Check' functions:   (these check for paradoxes, both active and passive)
+
+
+[CheckActiveParadox t action_de_jour trouble i j k flash_i_batteries flash_j_loc flash_j_batteries
+                    past_count present_count too_heavy;
+    action_de_jour = Get2D(dangerous_activity, t, my_time-EARLIEST_TIME-1);
+    trouble = false;
+
+    for (t=0 : t < time_travelled : t++) {
+        if (~~d_paradox) {
+            switch (action_de_jour) {
+                X_CCTV_:
+                    if (player in upstairs_corridor or ground_corridor or basement_corridor)
+                        trouble = true;
+                X_UPSTAIRS_CORRIDOR_:
+                    if (player in upstairs_corridor)
+                        trouble = true;
+                X_UPSTAIRS_LANDING_:
+                    if (player in upstairs_landing)
+                        trouble = true;
+                X_GROUND_CORRIDOR_:
+                    if (player in ground_corridor)
+                        trouble = true;
+                X_FOYER_:
+                    if (player in foyer)
+                        trouble = true;
+                X_BASEMENT_CORRIDOR_:
+                    if (player in basement_corridor)
+                        trouble = true;
+                X_BASEMENT_LANDING_:
+                    if (player in basement_landing)
+                        trouble = true;
+                X_BALCONY_:
+                    if (player in balcony)
+                        trouble = true;
+                TAKE_FLASHLIGHT_:
+                    for (i=0 : i<MAX_ITEM_COPIES : i++) {
+                        if ((flashlight-->i) in (former_self-->t)) {
+                            flash_i_batteries = BatteriesContained(flashlight-->i);
+                            past_count = 0;
+                            present_count = 0;
+                            for (j=0 : j < MAX_ITEM_COPIES : j++)
+                                if ((flashlight-->j) in (former_self-->t))
+                                    if (BatteriesContained(flashlight-->j) == flash_i_batteries)
+                                        present_count++;
+                            for (j=0 : j < MAX_ITEM_COPIES : j++) {
+                                flash_j_loc = Get3D(flashlight_loc,t,my_time-EARLIEST_TIME,j);
+                                flash_j_batteries = 0;
+                                for (k=0 : k<MAX_ITEM_COPIES : k++) {
+                                    if (Get3D(battery_loc,t,my_time-EARLIEST_TIME,k) == (flashlight-->j))
+                                        flash_j_batteries++;
+                                }
+                                if (flash_j_loc == former_self-->t)
+                                    if (flash_j_batteries == flash_i_batteries)
+                                        past_count++;
+                            }               
+                            if (present_count ~= past_count) {
+                                too_heavy = (past_count < present_count);
+                                trouble = true;
+                            }
+                        }
+                    }
+                BLOW_BASEMENT_LIGHT_:
+                    if (Get2D(basement_equipment_light, time_travelled, my_time-EARLIEST_TIME-1) == true)
+                        trouble = true;
+            }
+            if (trouble) {
+                d_paradox = true;
+                deadflag = 3;
+                Seperator();
+                switch (action_de_jour) {
+                    X_CCTV_:
+                        print "In the foyer, your past self glances at a CCTV screen and sees you in the 
+                               shadowed corridor.^";
+                    X_UPSTAIRS_CORRIDOR_:
+                        if (former_self-->t in balcony)
+                            print "From the chilly balcony, your former self looks through the glass door
+                                   and sees you in the shadowed corridor.^";
+                        else
+                            print "From the upstairs landing, your former self looks through the glass
+                                   and sees you in the shadowed corridor.^";
+                    X_UPSTAIRS_LANDING_:
+                        print "From the second floor corridor, your former self looks through the glass door
+                               and sees you in the shadowy landing.^";
+                    X_GROUND_CORRIDOR_:
+                        print "From within the foyer, your former self looks through
+                               the glass door and sees you in the shadowed corridor.^";
+                    X_FOYER_:
+                        if (former_self-->t in upstairs_landing)
+                            print "From the landing above, your former self looks down
+                                   and sees you.^";
+                        else
+                            print "From the first floor corridor, your former self looks through
+                                   the glass door and sees you.^";
+                    X_BASEMENT_CORRIDOR_:
+                        print "From the basement landing, your former self looks through the glass door
+                               and sees you in the shadowed corridor.^";
+                    X_BASEMENT_LANDING_:
+                        print "From the basement corridor, your former self looks through the glass door
+                               and sees you in the shadowy landing.^";
+                    X_BALCONY_:
+                        if (former_self-->t in upstairs_corridor)
+                            print "From the second floor corridor, your former self looks through the glass door
+                                   and sees you on the chilly balcony.^";
+                        else
+                            print "From within the darkened conference room, your former self looks out
+                                   and sees you on the chilly balcony.^";
+                    TAKE_FLASHLIGHT_:
+                        if (too_heavy)
+                            print (Nearby) 0, "your past self picks up a flashlight, but finds it
+                                   strangely heavy.^";
+                        else
+                            print (Nearby) 0, "your past self picks up a flashlight, but finds it
+                                   strangely light.^";
+                    BLOW_BASEMENT_LIGHT_:
+                        print "In the basement equipment room, your past self switches on the light
+                               but there is no flicker, for it has already blown.^";
+                }
+                if ((action_de_jour >= X_CCTV_) && (action_de_jour <= X_BALCONY_))
+                    print "^This is one of the all time most embarrassing ways
+                            to destroy the city of Boston.^";
+                print "^Time unravels...^";
+                Devours(my_time); 
+            }
+        }
+    }
+];
+
+
+[CheckPassiveParadox t;
+    for (t=0 : t < time_travelled : t++)
+        if (LocationOf(former_self-->t) ~= limbo) {
+            CheckPlayerInRoom(t);
+            CheckStateOfSiren(t);
+            
+            CheckStateOfDoors(t);
+
+            CheckStateOfGroundLight(t);
+    
+            CheckQuantityInRoom(bomb,bomb_loc,t);
+            CheckQuantityInRoom(id_card,id_card_loc,t);
+            CheckQuantityInRoom(equipment_key,equipment_key_loc,t);
+            CheckQuantityInRoom(deutsch_key,deutsch_key_loc,t);
+            CheckQuantityInRoom(flashlight,flashlight_loc,t);
+            CheckQuantityInRoom(battery,battery_loc,t);
+            CheckQuantityInRoom(cable,cable_loc,t);
+            CheckQuantityInRoom(crowbar,crowbar_loc,t);
+            CheckQuantityInRoom(notes,notes_loc,t);
+            
+            CheckStateOfFlashlights(t);
+    
+            if (former_self-->t in foyer)
+                CheckObjectsOnDesk(security_desk,t);
+            if (former_self-->t in conference_room) {
+                CheckObjectsOnDesk(conference_table,t);
+                CheckObjectsOnDesk(chair,t);
+            }
+            if (former_self-->t in deutsch_lab)
+                CheckObjectsOnDesk(bench,t);
+            if (former_self-->t in prototype_interior)
+                CheckTimeOnPanel(t);
+                
+            CheckTimesOnBombs(t);       
+        }
+];
+
+[CheckStateOfDoors t fs_loc;
+    fs_loc = LocationOf(former_self-->t);
+    
+    switch (fs_loc) {
+        foyer:
+            CheckStateOfDoor(main_doors, main_doors_state, t, fs_loc);
+            CheckStateOfDoor(ground_door, ground_door_state, t, fs_loc);
+            CheckBrokenDoor(main_doors, main_doors_smashed, t, fs_loc);
+            CheckBrokenDoor(ground_door, ground_door_smashed, t, fs_loc);
+        ground_corridor:
+            CheckStateOfDoor(ground_door, ground_door_state, t, fs_loc);
+            CheckBrokenDoor(ground_door, ground_door_smashed, t, fs_loc);
+            CheckStateOfDoor(ground_equipment_door, ground_equipment_door_state, t, fs_loc);
+        ground_equipment:
+            CheckStateOfDoor(ground_equipment_door, ground_equipment_door_state, t, fs_loc);
+        basement_landing:
+            CheckStateOfDoor(basement_door, basement_door_state, t, fs_loc);
+            CheckBrokenDoor(basement_door, basement_door_smashed, t, fs_loc);
+        basement_corridor:
+            CheckStateOfDoor(basement_door, basement_door_state, t, fs_loc);
+            CheckBrokenDoor(basement_door, basement_door_smashed, t, fs_loc);
+            CheckStateOfDoor(basement_equipment_door, basement_equipment_door_state, t, fs_loc);
+            CheckStateOfDoor(deutsch_door, deutsch_door_state, t, fs_loc);
+        deutsch_lab:
+            CheckStateOfDoor(deutsch_door, deutsch_door_state, t, fs_loc);
+        prototype_interior:
+            CheckStateOfDoor(deutsch_door, deutsch_door_state, t, fs_loc);
+        upstairs_landing:
+            CheckStateOfDoor(upstairs_door, upstairs_door_state, t, fs_loc);
+            CheckBrokenDoor(upstairs_door, upstairs_door_smashed, t, fs_loc);
+        upstairs_corridor:
+            CheckStateOfDoor(upstairs_door, upstairs_door_state, t, fs_loc);
+            CheckStateOfDoor(balcony_door, balcony_door_state, t, fs_loc);
+            CheckBrokenDoor(upstairs_door, upstairs_door_smashed, t, fs_loc);
+            CheckBrokenDoor(balcony_door, balcony_door_smashed, t, fs_loc);
+        balcony:
+            CheckStateOfDoor(balcony_door, balcony_door_state, t, fs_loc);
+            CheckBrokenDoor(balcony_door, balcony_door_smashed, t, fs_loc);
+            CheckStateOfDoor(conference_window, conference_window_state, t, fs_loc);
+        conference_room:
+            CheckStateOfDoor(conference_window, conference_window_state, t, fs_loc);
+        default:
+            return false;
+    }
+];
+
+! this is a tiny bit of a hack, using the fact that OPEN_ is higher than CLOSED_, LOCKED_.
+! and the fact that automatic doors which are open have values higher than OPEN_.
+
+[CheckStateOfDoor door door_state t fs_loc past_door_state fs_loc_last_turn;
+    past_door_state = Get2D(door_state,t,my_time-EARLIEST_TIME);
+    fs_loc_last_turn = Get2D(player_loc,t,my_time-EARLIEST_TIME-1);
+
+    if (~~d_paradox) {
+        if ((past_door_state >= OPEN_) && (door hasnt open)) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                  " and sees ", (the) door, " pulled closed.^"; 
+            print "^Time unravels...^";
+            Devours(my_time);                            
+        }
+        else if ((past_door_state < OPEN_) && (door has open)) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            if (door ~= conference_window) {
+                if (fs_loc_last_turn ~= fs_loc)
+                    print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                          " and sees ", (the) door, " standing open.^";      
+                else
+                    print (Nearby) 0, "your former self standing in ", (TheLower) fs_loc,
+                          " sees ", (the) door, " open.^";   
+            }   
+            else
+                print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                      " and sees the shattered conference room window.^";                         
+            print "^Time unravels...^";
+            Devours(my_time); 
+        }
+    }
+];
+
+
+[CheckBrokenDoor door door_smashed t fs_loc past_door_smashed_now past_door_smashed_next;
+    past_door_smashed_now  = Get2D(door_smashed,t,my_time-EARLIEST_TIME-1);
+    past_door_smashed_next = Get2D(door_smashed,t,my_time-EARLIEST_TIME);
+    if (~~d_paradox) {
+        if ((~~past_door_smashed_next) && door.smashed) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            if (past_door_smashed_now)
+                print "In ", (TheLower) fs_loc, ", your former self sees the web of cracks in ",
+                      (the) door, ".^"; 
+            else
+                print "In ", (TheLower) fs_loc, ", your former self hears the crack of your
+                       crowbar smashing into ",
+                      (the) door, ".^"; 
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+    }
+
+];
+
+[CheckTimesOnBombs t i j bomb_i_time bomb_j_time bomb_j_loc 
+                   past_count present_count fs_loc;
+                   
+    fs_loc = LocationOf(former_self-->t);
+    
+    if (~~d_paradox) {
+        for (i=0 : i < MAX_ITEM_COPIES : i++) {
+            if (LocationOf(bomb-->i) == fs_loc) {
+                bomb_i_time = (bomb-->i).time_value;
+                past_count = 0;
+                present_count = 0;
+                for (j=0 : j < MAX_ITEM_COPIES : j++)
+                    if (LocationOf(bomb-->j) == fs_loc)
+                        if ((bomb-->j).time_value == bomb_i_time)
+                            present_count++;
+                for (j=0 : j < MAX_ITEM_COPIES : j++) {
+                    bomb_j_loc = Get3D(bomb_loc,t,my_time-EARLIEST_TIME,j);
+                    bomb_j_time = Get3D(bomb_setting,t,my_time-EARLIEST_TIME,j);
+                    if (((bomb_j_loc == fs_loc) || (parent(bomb_j_loc) == fs_loc)))
+                        if (bomb_j_time == bomb_i_time)
+                            past_count++;
+                }               
+                if (past_count ~= present_count) {
+                    d_paradox = true;
+                    deadflag = 3;
+                    Seperator();
+                    print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                          " and sees a different value flashing on the explosive device's
+                           timer.^"; 
+                    print "^Time unravels...^";
+                    Devours(my_time);                            
+                }
+            }
+        }
+    }
+
+];
+
+[CheckStateOfFlashlights t i present_flashlights_on past_flashlights_on
+                         fs_loc flash_loc flash_state;
+    fs_loc = LocationOf(former_self-->t);
+    if (~~d_paradox) {
+        for (i=0 : i < MAX_ITEM_COPIES : i++) {
+            flash_loc = Get3D(flashlight_loc,t,my_time-EARLIEST_TIME,i);
+            flash_state = Get3D(flashlight_state,t,my_time-EARLIEST_TIME,i);
+            if (flash_state && ((flash_loc == fs_loc) || (parent(flash_loc) == fs_loc)))
+                past_flashlights_on++;
+            if ((flashlight-->i has on) && (LocationOf(flashlight-->i) == fs_loc))
+                present_flashlights_on++;
+        }
+        if (past_flashlights_on ~= present_flashlights_on) {
+                d_paradox = true;
+                deadflag = 3;
+                Seperator();
+                if (past_flashlights_on < present_flashlights_on)
+                    print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                          " and sees a thin white beam of light shining where once
+                           was darkness.^"; 
+                else
+                    print (Nearby) 0, "your former self enters ", (TheLower) fs_loc,
+                          " and sees only darkness where once a thin white beam of light
+                            was shining.^";
+                print "^Time unravels...^";
+                Devours(my_time);        
+        }
+    }
+];
+
+! only need to check if in corridor with open door as this will catch all cases
+
+[CheckStateOfGroundLight t past_ground_light_state;
+    past_ground_light_state = Get2D(ground_equipment_light,t,my_time-EARLIEST_TIME);
+
+    if (~~d_paradox)
+        if ((ground_light_switch has on) ~= past_ground_light_state) {
+            if ((former_self-->t in ground_corridor) && (ground_equipment_door has open)) {
+                d_paradox = true;
+                deadflag = 3;
+                Seperator();
+                if (ground_light_switch has on) {
+                    if (Get2D(ground_equipment_door_state,t,my_time-EARLIEST_TIME-1)==OPEN_)
+                        print (Nearby) 0, "your former self enters the first floor corridor
+                               and sees a pool of light spilling from the equipment room.^"; 
+                    else
+                        print (Nearby) 0, "your former self opens the door to the first floor
+                               equipment room and bright fluorescent light
+                               spills over her.^";
+                }
+                else {
+                    if (Get2D(ground_equipment_door_state,t,my_time-EARLIEST_TIME-1)==OPEN_)
+                        print (Nearby) 0, "your former self enters the first floor corridor
+                               but does not see a pool of light spilling from the
+                               equipment room.^"; 
+                    else
+                        print (Nearby) 0, "your former self opens the door to the first floor
+                               equipment room but no bright fluorescent light
+                               spills over her.^";
+                }
+                print "^Time unravels...^";
+                Devours(my_time);
+            }
+        }
+];
+
+[CheckStateOfSiren t past_state siren_on;
+    past_state = Get2D(siren_state,t,my_time-EARLIEST_TIME);
+    siren_on = (siren_start_time ~= UNKNOWN_) && (siren_start_time < my_time);
+
+    if (~~d_paradox)
+        if (past_state ~= siren_on) {
+                if (my_time - siren_start_time == 1)
+                    print "^A piercing siren rings out.^";
+                if (my_time - siren_start_time > 1)
+                    print "^The siren wails.^";
+                d_paradox = true;
+                deadflag = 3;
+                Seperator();
+                print (Nearby) 0, "your former self cringes from the sound of the siren.^"; 
+                print "^Time unravels...^";
+                Devours(my_time);
+            }
+];
+
+
+!! Only checks the bare contents of the room, not the containers, states etc.
+
+[CheckQuantityInRoom thing_type thing_loc t i present_count past_count;
+    present_count = 0;
+    past_count = 0;
+    
+    if (~~d_paradox) {
+        for (i=0 : i < Exp(2,t+1) : i++) {
+            if (parent(thing_type-->i) == LocationOf(former_self-->t))
+                present_count++;  
+            if (Get3D(thing_loc,t,my_time-EARLIEST_TIME,i) == LocationOf(former_self-->t))
+                past_count++;
+        }
+        if (past_count ~= present_count) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "Entering ", (TheLower) LocationOf(former_self-->t),
+                  " your past self looks quickly about. ";
+            if (past_count > present_count)
+                print "Unlike the last time, her gaze passes straight over the place
+                       where ", (the) thing_type-->0,
+                      " had lain.^"; 
+            else
+                print "As her glance falls upon ", (the) thing_type-->0,
+                      " a moment of worry passes over her features.^"; 
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+    }
+];
+
+[CheckPlayerInRoom t player_loc_now player_loc_next fs_loc_now fs_loc_next;
+
+    player_loc_now  = Get2D(player_loc,time_travelled,my_time-EARLIEST_TIME-1);
+    player_loc_next = Get2D(player_loc,time_travelled,my_time-EARLIEST_TIME);
+    fs_loc_now      = Get2D(player_loc,t,my_time-EARLIEST_TIME-1);
+    fs_loc_next     = Get2D(player_loc,t,my_time-EARLIEST_TIME);
+
+    if ((player_loc_next == fs_loc_next)) {
+        if (player_loc_now == nothing) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "Someone appears beside you in the cramped chamber.
+                   Soft hair and anxious eyes. It is you.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+        else if (player_loc_now ~= player_loc_next) {    !! if the player had moved...
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "As you enter ", (TheLower) player_loc_next,
+                  " you see your former self standing before you.
+                   Hearing your soft footfall, she turns. Horror fills her eyes.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+        else if (fs_loc_now ~= fs_loc_next) {       !! if the former self had moved...
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "You turn at the sound of footsteps. It is you.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+        else
+            print "Error, former self saw player but neither had moved.^";
+    }
+    else if ((player_loc_next == fs_loc_now) && (player_loc_now == fs_loc_next)) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "As you enter ", (TheLower) player_loc_next,
+                  ", your eyes catch upon a figure coming towards you.
+                   She pauses, fear all about her.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+    }
+    else if ((player_loc_next == deutsch_lab) && (fs_loc_next == prototype_interior)) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "Hunched inside the prototype, your former self sees you through the open
+                   hatch.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+    }
+    else if ((player_loc_next == prototype_interior) && (fs_loc_next == deutsch_lab)) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "As your past self looks around, her eyes catch on
+                   something inside the prototype.^";
+            print "^Time unravels...^";
+            Devours(my_time);
+    }
+    
+];
+
+[CheckObjectsOnDesk desk t;
+    CheckObjectOnDesk(desk, t, bomb, bomb_loc);
+    CheckObjectOnDesk(desk, t, id_card, id_card_loc);
+    CheckObjectOnDesk(desk, t, equipment_key, equipment_key_loc);
+    CheckObjectOnDesk(desk, t, deutsch_key, deutsch_key_loc);
+    CheckObjectOnDesk(desk, t, flashlight, flashlight_loc);
+    CheckObjectOnDesk(desk, t, battery, battery_loc);
+    CheckObjectOnDesk(desk, t, cable, cable_loc);
+    CheckObjectOnDesk(desk, t, crowbar, crowbar_loc);
+    CheckObjectOnDesk(desk, t, notes, notes_loc);            
+];
+
+[CheckObjectOnDesk desk t thing_type thing_loc present_count past_count i;
+    if (~~d_paradox) {
+        for (i=0 : i < Exp(2,t+1) : i++) {
+            if (thing_type-->i in desk)
+                present_count++;
+            if (Get3D(thing_loc,t,my_time-EARLIEST_TIME,i) == desk)
+                past_count++;
+        }
+        if (past_count ~= present_count) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "Entering ", (TheLower) LocationOf(former_self-->t),
+                  " your past self looks quickly about. ";
+            if (past_count > present_count)
+                print "Unlike the last time, her gaze passes straight over the place
+                       on ", (the) desk, " where ", (the) thing_type-->0,
+                      " had lain.^"; 
+            else
+                print "As her glance falls upon ", (the) thing_type-->0,
+                      " a moment of worry passes over her features.^"; 
+            print "^Time unravels...^";
+            Devours(my_time);
+        }
+    }
+];
+
+[CheckTimeOnPanel t old_setting;
+    old_setting = Get2D(panel_setting, t, my_time-EARLIEST_TIME);
+    if (~~d_paradox)
+        if (control_panel.time_value ~= old_setting) {
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print "Entering the prototype, your past self glances at the control panel,
+                   seeing ", control_panel.time_value, " instead of ", old_setting, ".^"; 
+            print "^Time unravels...^";
+            Devours(my_time);        
+        }
+];
+
+
+!----------------------------------------------------
+!
+! Endgame functions:
+
+
+[CaughtInside t;
+    d_caught = true;
+
+!-- Initial method of being caught:
+        
+    if (my_time > FINAL_TIME)
+        print "^A quick noise from behind, then a strong grip on your wrist.
+               The guard is back -- time has slipped away from you.^";
+    else if ((siren_start_time ~= UNKNOWN_) && (my_time - siren_start_time > siren_timeout))
+        print "^As the siren shrieks out around you, you catch a glimpse of movement.
+               A sudden jolt, then you are wrestled to the ground. Security has arrived.^";
+    else
+        print "Error: unknown reason for being caught^";
+    
+!-- Allow a small amount of time for bomb to explode before player dragged off...
+    
+    for (t=0 : (t<TIME_BEFORE_DRAGGED_OFF) && (my_time<FINAL_TIME) && (~~d_exploded) : t++) {
+        IncTime();    ! as it happens, this can lead to bomb-explosion, but not paradox
+    }
+    
+    if (~~d_exploded)     ! make sure player is dragged off
+        DragPlayerOff();
+];
+
+[Jumped;
+    if (~~warned_of_jump) {
+        print "It is a large drop and you are not at all sure that you could make it
+               without serious injury.^";
+        warned_of_jump = true;
+        return true;
+    }
+    
+    d_caught = true;
+
+!-- Initial method of being caught:
+        
+    print "You hit the ground hard and collapse. Your right ankle sears with pain.
+           Before you can stand, you see the security guard running swiftly towards you.^";
+    
+    DragPlayerOff();
+];
+
+
+[DragPlayerOff t;
+
+    print "^Deaf to your protests, the guard ";
+    if (AmHolding(bomb) && ((GetHeld(bomb)).time_value ~= NA_))
+        print "disarms your bomb, ";
+    print "handcuffs you and forces you
+           into a dark sedan. You speed through the chill Boston night, head held in your hands,
+           almost oblivious to the blur of the suburbs rushing past.^";
+
+    d_detained = true;
+    move player to limbo;
+    
+!-- Allow some more time for bomb to explode
+!-- and for paradoxes to occur
+
+    for (t=0 : (my_time<FINAL_TIME) && (~~d_exploded) && (~~d_paradox) : t++) {
+        IncTime();
+    }
+    
+    MaybeExplodeBombAfterwards();
+        
+    deadflag = 3;
+        
+!-- Consequences of being caught:
+
+    if (~~d_paradox) {
+        print "^Half an hour later, the car pulls up outside a non-descript building and you
+                are dragged inside";
+        if (AmHolding(notes))
+            print ", the notes are taken from you and you are ";
+        else
+            print " then ";
+        print "thrown into a small cell to await questioning.^";
+                
+        if (d_exploded) {
+            if (d_destroyed_prototype && d_destroyed_notes) {
+                print "^The months that follow are a nightmare. Solitary confinement, sleepless nights,
+                        merciless interrogations. Eventually, you are taken before a civilian court and
+                        tried for treason. A drawn-out trial, a guilty verdict, prison. Ambitions falter and
+                        then fade. Still, as the months and then years pass, they do not bring the disaster
+                        you had so feared and you cling, anxiously, longingly, to the dream that it was you who brought
+                        this about, that your sacrifice was not in vain.^";
+                my_time = NA_;
+                DrawStatusLine();
+                deadflag = SAVED_CAUGHT_;
+           }
+!            else if (d_destroyed_prototype && AmHolding(notes)) {
+!            }
+            else if (d_destroyed_prototype) {
+                print "^The days that follow are a nightmare. Solitary confinement, sleepless nights,
+                        merciless interrogations. All that keeps you going is the small hope that your actions
+                        were not in vain.^";
+                Seperator();
+                print "With your research notes at hand, the military scientists painstakingly rebuild the
+                       prototype and prepare it for testing.^";
+            }
+!            else if (d_destroyed_notes) {
+!                print " ";
+!            }            
+!            else if (AmHolding(notes)) {
+!                print " ";
+!            }        
+!            else {
+!                print " ";
+!            }
+        }          
+!        else if (AmHolding(bomb) && AmHolding(notes)) {
+!            print " ";
+!        }
+!        else if (AmHolding(bomb)) {
+!            print " ";
+!        }
+!        else if (AmHolding(notes)) {
+!            print " ";
+!        }
+!        else {
+!            print " ";
+!        }
+
+        if ((~~d_destroyed_prototype) || (~~d_destroyed_notes))         
+           MilitaryTest(); 
+    }
+];
+
+[InBlastRadius thing bomb;
+    if (LocationOf(thing) == LocationOf(bomb))
+        return true;
+    if ((LocationOf(bomb) == deutsch_lab) && (LocationOf(thing) == prototype_interior))
+        return true;
+    if ((LocationOf(bomb) == prototype_interior) && (LocationOf(thing) == deutsch_lab))
+        return true;
+    return false;
+];
+
+[MaybeExplodeBombAfterwards i j;
+    if (~~d_exploded)
+        for (i=0 : i<MAX_ITEM_COPIES : i++)
+            if (((bomb-->i).time_value >= FINAL_TIME) && ~~(bomb-->i in player)) {
+                d_exploded = true;
+                if (LocationOf(bomb-->i) == deutsch_lab or prototype_interior)
+                    d_destroyed_prototype = true;
+                for (j=0 : j < MAX_ITEM_COPIES : j++)
+                    if (InBlastRadius(notes-->j,bomb-->i))
+                        d_destroyed_notes = true;
+            }
+];
+
+[ExplodeBomb i j t;
+
+    if (d_exploded)
+        return true;
+        
+    d_exploded = true;
+
+!-- what exploded?
+          
+    if ((~~(d_escaped || d_detained)) && InBlastRadius(player,bomb-->i) )
+        d_killed_by_bomb = true;
+    if (~~(d_escaped || d_detained))
+        d_injured_by_bomb = true;
+    if (LocationOf(bomb-->i) == deutsch_lab or prototype_interior)
+        d_destroyed_prototype = true;
+    for (j=0 : j < MAX_ITEM_COPIES : j++)
+        if (InBlastRadius(notes-->j,bomb-->i))
+            d_destroyed_notes = true;
+    for (t=0 : t < time_travelled : t++)
+        if (InBlastRadius(former_self-->t, bomb-->i)) {
+            d_fs_killed_by_bomb = true;
+            d_paradox = true;
+        }
+    for (t=0 : t < time_travelled : t++)
+        if ((LocationOf(former_self-->t) ~= limbo)) {
+            d_fs_hears_bomb = true;
+            d_paradox = true;
+        }
+    
+!-- Consequences of explosion
+
+    if (d_killed_by_bomb == true) {
+        print "^The bomb detonates. A wall of force rips through the room with savage
+               power, killing you immediately.^";
+        if (~~d_fs_hears_bomb) {
+            for (t=0 : (my_time<FINAL_TIME) && (~~d_paradox) : t++) {
+                IncTime();
+            }
+            deadflag = 3;
+            if ((~~d_paradox) && d_destroyed_prototype && d_destroyed_notes) {
+                my_time = NA_;
+                DrawStatusLine();
+                deadflag = SAVED_DEAD_;
+            }
+            else 
+                MilitaryTest();
+        }
+    }
+    else if (d_injured_by_bomb) {
+        print "^The bomb detonates. You are knocked to the floor by the force of the
+               explosion and your ears ring. ";
+        if (~~d_fs_hears_bomb) {
+            print "Stunned, you lie prone on the floor as
+                   the siren wails and the reek of smoke stings your nostrils.^^
+                   Before you recover your senses, security is upon you.^";
+            DragPlayerOff(); 
+        }
+        else
+            print "^";
+    }
+       
+    if (d_fs_killed_by_bomb) {
+        Seperator();
+        if (d_detained || d_escaped)
+            print "Across town, the bomb detonates.
+                   The explosion tears into your former self and she falls lifeless to
+                   the ground.^";
+        else     
+            print (Nearby) 0, "the explosion tears into your former self and she falls lifeless to
+                   the ground.^";
+        print "^Time unravels...^";
+        Devours(my_time);
+    }
+    else if (d_fs_hears_bomb) {
+        Seperator();
+        if (d_detained || d_escaped)
+            print "Across town, the bomb detonates.
+                   Your former self is brought to her knees by the sudden blast,
+                   the horror of understanding written in her eyes.^";
+        else
+            print (Nearby) 0, "your former self is brought to her knees by the sudden blast,
+                   the horror of understanding written in her eyes.^";
+        print "^Time unravels...^";
+        Devours(my_time);
+    }
+
+    
+];
+
+[Escaped t;
+    d_escaped = true;
+
+    move player to outside;
+
+!-- result of escaping:
+  
+    print "^";
+        
+    if (my_time >= FINAL_TIME - 3) {
+        print "The night beckons you from the open doors, but as you rush
+               forwards to meet it your hopes fail you -- security has arrived.^";
+        d_caught = true;
+        DragPlayerOff();  
+    }
+    else if ((siren_start_time ~= UNKNOWN_) && (my_time - siren_start_time > siren_timeout - 2)) {
+        print "The night beckons you from the open doors, but as you rush
+               forwards to meet it your hopes fail you. With the siren shrieking out around you, 
+               security has arrived.^";
+        d_caught = true;
+        DragPlayerOff();   
+    }
+          
+!-- Deal with the true escapes:
+    
+    else {
+        move player to limbo;
+        
+        print "You slip out into the night, darting quickly through the Cambridge
+               shadows until you reach the quiet corner where you left your car.
+               Exhausted, you gently start the cold motor and roll off towards the
+               interstate.^";
+                
+!-- Step through the rest of the time to check for paradox and/or explosion
+        
+        for (t=0 : (my_time<FINAL_TIME) && (~~d_paradox) : t++) {
+            IncTime();
+        }
+
+        MaybeExplodeBombAfterwards();
+     
+        deadflag = 3;
+            
+!-- Final wrap-up:
+
+        if (~~d_paradox) {
+            if (d_exploded) {
+                if (d_destroyed_prototype && d_destroyed_notes) {
+                    print "^Days, months, years run by. 
+                            You find a new name, a new life. 
+                            Fresh challenges are gladly met and life proceeds with full force in its
+                            new and welcome direction. 
+                            Only now and then do you stop on a chill starry night and
+                            wonder whether you were right, what really would have happened.^";
+                    my_time = NA_;
+                    DrawStatusLine();
+                    deadflag = SAVED_FREE_;
+               }
+                else if (d_destroyed_prototype && AmHolding(notes) && challenge) {
+                    print "^Days, months, years run by. 
+                            You find a new name, a new life. 
+                            You travel abroad.
+                            Eventually, you look again at your time-stained research notes
+                            and think of the possibilities.^^
+                            The inconsistencies are the key; the freed energy.
+                            Maybe now, without the shadow of military interests, you could
+                            make something of this.^";
+                    my_time = NA_;
+                    DrawStatusLine();
+                    deadflag = SAVED_FREE_CHALLENGE_;
+                }
+                else if (d_destroyed_prototype && AmHolding(notes)) {
+                    print "^Days, months, years run by. 
+                            You find a new name, a new life. 
+                            Fresh challenges are gladly met and life proceeds with full force in its
+                            new and welcome direction. 
+                            Only now and then do you stop on a chill starry night and
+                            wonder whether you were right, what really would have happened.^";
+                    my_time = NA_;
+                    DrawStatusLine();
+                    deadflag = SAVED_FREE_;
+                }
+                else if (d_destroyed_prototype) {
+                    print "^Days run by. You find a new name, begin a new life.
+                            You hope, pray, that all you have done will stop them, that the
+                            catastrophe will not come.^";
+                    Seperator();
+                    print "With your research notes at hand, the military scientists painstakingly rebuild the
+                           prototype and prepare it for testing.^";
+                    deadflag = DELAYED_;
+                }
+!                else if (d_destroyed_notes) {
+!                    print "^Escape: ~d-prototype + d-notes.^";
+!                }    
+!                else if (AmHolding(notes)) {
+!                    print "^Escape: useless explosion + holding notes.^";
+!                }        
+                else {
+                    print "^Morning finds you in a truck-stop cafe, near Woodstock, NY. You sit there,
+                            anxiously watching the morning news as you sip your bitter coffee.^";
+                }
+            }          
+!            else if (AmHolding(bomb) && AmHolding(notes)) {
+!                print "^Escape: holding bomb + notes.^";
+!            }
+!            else if (AmHolding(bomb)) {
+!                print "^Escape: holding bomb.^";
+!            }
+!            else if (AmHolding(notes)) {
+!                print "^Escape: holding notes.^";
+!            }
+            else {
+                    print "^Morning finds you in a truck-stop cafe, near Woodstock, NY. You sit there,
+                            anxiously watching the morning news as you sip your bitter coffee.^";
+            }
+    
+            if (~~(d_destroyed_prototype && (d_destroyed_notes || AmHolding(notes)))) {
+               MilitaryTest(); 
+            }
+        }
+    }
+];
+
+! tests whether something has happened to stop the player continuing their actions
+
+[Stopped;
+    if (d_paradox || d_caught || d_exploded || d_escaped)
+        return true;
+    else
+        return false;
+];
+
+[Seperator;
+    print "^*******^^";
+];
+
+[MilitaryTest;
+    Devours(LATER_);
+];
+
+[Devours given_time explosion_time;
+    
+    Seperator();
+    if (given_time == LATER_) {
+        if (d_destroyed_prototype) {
+            print "Monday 1st November 2004^^";
+            explosion_time = EXPERIMENT2_TIME;
+            deadflag = DELAYED_;
+        }
+        else {
+            print "Wednesday 13th October 2004^^";
+            explosion_time = EXPERIMENT1_TIME;
+            deadflag = USELESS_;
+        }
+    }
+    else {
+        print "Tuesday 12th October 2004^^";
+        deadflag = ACCELERATED_;
+        explosion_time = last_travel_time; 
+    }
+    
+    !my_time = explosion_time;   ! these lines would update the status line time
+    !DrawStatusLine();
+
+    if (poem_interleaving) {
+        print "At precisely ", (PrintShortTime) explosion_time, " this morning ";
+        
+        PoemStyleOn();
+        print "This thing all things devours: ";
+        PoemStyleOff();
+    
+        print "a catastrophe of unprecedented scale occurred. ";
+            
+        PoemStyleOn();
+        print "birds, beasts, trees, flowers; ";
+        PoemStyleOff();
+        
+        print "An immense explosion -- that could only have been atomic in nature -- ";
+        
+        PoemStyleOn();
+        print "gnaws iron, bites steel; ";
+        PoemStyleOff();   
+        
+        print "tore through the city and suburbs of Boston MA, destroying all in its path. ";
+        
+        PoemStyleOn();
+        print "grinds hard stones to meal; ";
+        PoemStyleOff();   
+    
+        print "Casualties will number in the millions and martial law has been declared. ";
+    
+        PoemStyleOn();
+        print "slays king, ruins town; ";
+        PoemStyleOff();   
+        
+        print "The military is mobilizing for war with the as yet unknown enemy. ";
+        
+        PoemStyleOn();
+        print "and beats high mountain down. ";
+        PoemStyleOff();   
+        
+        print "^";
+    }
+    else {
+        print "At precisely ", (PrintShortTime) explosion_time, " this morning 
+               a catastrophe of unprecedented scale occurred. 
+               An immense explosion -- that could only have been atomic in nature --
+               tore through the city and suburbs of Boston MA, destroying all in its path.
+               Casualties are expected to number in the millions. The President has declared
+               a state of emergency across the nation and
+               the military is mobilizing for a possible war with the as yet unknown enemy.^^";
+        PoemStyleOn();
+        print "This thing all things devours:^";
+        print "birds, beasts, trees, flowers;^";
+        print "gnaws iron, bites steel;^";
+        print "grinds hard stones to meal;^";
+        print "slays king, ruins town;^";
+        print "and beats high mountain down.^";
+        PoemStyleOff();   
+    }
+
+];
+
+[PoemStyleOn;
+    style bold;
+];
+
+[PoemStyleOff;
+    style roman;
+];
+
+[ DeathMessage; 
+    switch (deadflag) {
+        ACCELERATED_:            print "You have failed";
+        USELESS_:                print "You have failed";
+        DELAYED_:                print "You have failed";
+        SAVED_DEAD_:             print "Success, but at such a cost";
+        SAVED_CAUGHT_:           print "Success, but at such a cost";
+        SAVED_FREE_:             print "Success. Final, lasting success."; 
+        SAVED_FREE_CHALLENGE_:   print "Success and, perhaps, a new hope."; 
+    }
+];
+
+[Nearby;
+    if (~~(player in limbo))
+        print "Nearby, ";
+    else
+        print "Back at the lab, ";
+];
+
+[TheLower room;
+    print (string) room.lower_name;
+];
+
+
+
+!============================================================================
+
+! Include "../Contrib/Scenic";
+
+
+!============================================================================
+
+! Standard and extended grammar
+
+
+
+Include "Grammar";
+
+
+!----------------------------------------------------------------------------
+
+[ AboutSub;
+  instant_action_this_turn = true;
+  print "^All Things Devours is a short piece of interactive fiction, leaning strongly
+          towards the text-adventure end of the spectrum. It explores an all-too-familiar
+          science fiction paradigm in what I hope is a rather refreshing and satisfying manner.
+          However, due to the intrinsic nature of its subject matter, it is more cruel
+          than one might hope for a modern piece of interactive fiction. In particular,
+          any move you make may put things into an unwinnable state. You are therefore encouraged
+          to save frequently, and also to realise that you will probably have to start over several times
+          to find the most satisfactory ending.^^
+          Hints, reviews and more can be found at http://devours.amirrorclear.net^";
+];
+
+Verb 'about'
+    * 'game'                        -> About
+    * 'devours'                     -> About
+    * 'all' 'things' 'devours'      -> About
+    *                               -> About;
+
+[ WalkthroughSub;
+  instant_action_this_turn = true;
+  print_ret "Hints and a walkthrough are located at http://devours.amirrorclear.net^
+             You might also want to try the 'about' command.^^
+             If you are unfamiliar with text adventures, then you may want to
+             learn the basics first at an introductory website such as
+             http://brasslantern.org/beginners/"; ];
+
+Verb 'walkthrough' 'walkthru' 'hint' 'hints' 'help'
+    *                               -> Walkthrough;
+
+[ CreditsSub;
+  instant_action_this_turn = true;
+  print_ret "Written by half sick of shadows for IFComp 2004.^
+             Beta tested by Stephen Bond.^
+             Special thanks go to those who submitted detailed bug reports and suggestions
+             during the competition, notably: Peter Eckersley, Oliver Nash,
+             Hugo Thorvaldsen and Evin Robertson.^
+             ^
+             No rights are reserved by the author:
+             this work is in the public domain and may be freely copied and modified.";
+];
+
+Verb 'credits'
+    *                               -> Credits;
+
+[ InterleavingOnSub;
+  instant_action_this_turn = true;
+  poem_interleaving = true;
+  "The ending will now be in the original, interleaved, style.";
+];
+
+[ InterleavingOffSub;
+  instant_action_this_turn = true;
+  poem_interleaving = false;
+  "The ending will now be in the standard style.";
+];
+
+Verb 'interleaving'
+    * 'on'                              -> InterleavingOn
+    * 'off'                             -> InterleavingOff;
+
+[ ResetSub; print_ret "It is not clear what you are trying to do."; ];
+
+Verb 'reset' 'stop' 'halt' 'defuse'
+    * noun                          -> Reset;
+
+Verb 'swipe'
+    * noun 'in' noun                -> Insert
+    * noun 'through' noun           -> Insert;
+
+[ CompleteModificationsSub; 
+    if ((real_location == deutsch_lab) || (real_location == prototype_interior))
+        <<Tie prototype>>;
+    else
+        "You would need to be near the prototype to do that.";
+];
+
+Verb 'complete' 'finish'
+    * 'modifications'                     -> CompleteModifications
+    * 'work'                              -> CompleteModifications
+    * 'changes'                           -> CompleteModifications
+    * 'alteration'                        -> CompleteModifications;
+
+[ ModifySub; 
+    if ((noun == prototype) || (noun == control_panel) || (noun == nothing)) {
+        if ((real_location == deutsch_lab) || (real_location == prototype_interior)) 
+            <<Tie prototype>>;
+        else
+            "You would need to be near the prototype to do that.";
+    }
+    "It is not clear what you are trying to do.";
+];
+
+Verb 'modify' 'change' 'alter'
+    *                          -> Modify
+    * noun                     -> Modify;
+
+[ SwitchSub; 
+    if (noun has on)
+        <<SwitchOff noun>>;
+    else
+        <<SwitchOn noun>>;
+];
+
+Verb 'flick' 'flip'
+    * noun                     -> Switch;
+    
+Extend 'switch' first
+    * noun                     -> Switch;
+
+[ SwingAtSub; if (second == nothing)
+                  print_ret "You swing ", (the) noun, " through the air, harmlessly.";
+              else if (IsOfType(noun, crowbar))
+                  <<Attack second>>;
+              else if ((second == conference_window) || (second ofclass AutomaticDoor)) {
+                  print_ret (The) noun, " bounces harmlessly off the ",
+                            (the) second, ".";
+              }
+              else
+                  <<Attack noun>>;
+];
+
+Extend 'swing' first
+    * held                          -> SwingAt
+    * held 'at' noun                -> SwingAt
+    * held 'into' noun              -> SwingAt
+    * held 'through' noun           -> SwingAt;
+    
+
+[ AttackWithSub; if (IsOfType(second, crowbar))
+                     <<Attack noun>>;
+                 else if ((noun == conference_window) || (noun ofclass AutomaticDoor)) {
+                     if (second == nothing)
+                         print_ret "You are not strong enough to break ",
+                                   (the) noun, " by yourself.";
+                     else
+                         print_ret (The) second, " is not heavy enough to break ",
+                                   (the) noun, ".";
+                 }
+                 else
+                     <<Attack noun>>;
+];
+
+Extend 'attack'
+    * noun 'with' 'fist'            -> AttackWith
+    * noun 'with' 'foot'            -> AttackWith
+    * noun 'with' 'hand'            -> AttackWith
+    * noun 'with' held              -> AttackWith;
+
+[ JumpDownSub; if (real_location == balcony)
+                   Jumped();
+               else if ((real_location == upstairs_landing) || (real_location == foyer)) {
+                   print "You hit the ground hard. Maybe you should have used the stairs.^";
+                   <<Go d_obj>>;
+               }
+               else
+                   "There is nothing to jump down to.";
+];
+
+Extend 'jump' first
+    * 'down'                        -> JumpDown;
+
+[ ClimbDownSub; if (real_location == balcony)
+                   Jumped();
+               else if ((real_location == upstairs_landing) || (real_location == foyer))
+                   <<Go d_obj>>;
+               else
+                   "There is nothing to climb down to.";
+];
+
+Extend 'climb' first
+    * 'down'                        -> ClimbDown;
+
+[ LockSimpleSub k;
+if (noun has lockable) {
+     if (noun.with_key_type == nothing)
+         "You do not have the key.";         
+     k = GetHeld(noun.with_key_type);
+     if (k == nothing)
+         "You do not have the key.";
+     <<Lock noun k>>;
+ }
+ else 
+     "That doesn't seem to be something you can lock.";
+
+];
+
+Extend 'lock' first
+    * noun                        -> LockSimple;
+
+
+[ UnlockSimpleSub k;
+if (noun has lockable) {
+     if (noun.with_key_type == nothing)
+         "You do not have the key.";         
+     k = GetHeld(noun.with_key_type);
+     if (k == nothing)
+         "You do not have the key.";
+     <<Unlock noun k>>;
+ }
+ else 
+     "That doesn't seem to be something you can unlock.";
+
+];
+
+Extend 'unlock' first
+    * noun                        -> UnlockSimple;
+
+[ UseSub;
+  "You will have to be more specific about your action.";
+];
+
+Verb 'use' 
+    *                             -> Use
+    * noun                        -> Use;
+
+[ PlantSub p;
+  p = parent(noun);
+  <Drop noun>;
+  if (parent(noun) ~= p)
+      if (noun ofclass Bomb_)
+          if (noun.time_value == NA_)
+              "(you may also want to set the timer)";
+];
+
+[ PlantInSub p;
+  p = parent(noun);
+  <Insert noun second>;
+  if (parent(noun) ~= p)
+      if (noun ofclass Bomb_)
+          if (noun.time_value == NA_)
+              "(you may also want to set the timer)";
+];
+
+[ PlantOnSub p;
+  p = parent(noun);
+  <PutOn noun second>;
+  if (parent(noun) ~= p)
+      if (noun ofclass Bomb_)
+          if (noun.time_value == NA_)
+              "(you may also want to set the timer)";
+];
+
+Verb 'plant' 
+    * noun                        -> Plant
+    * noun 'in' noun              -> PlantIn
+    * noun 'on' noun              -> PlantOn;
+
+Extend 'look'
+    * noun                        -> Examine;
+
+[ WaitSecondsSub t;
+  if (noun == 0) {
+      instant_action_this_turn = true;
+      "That didn't take long.";  
+  }
+  if (noun < 0) {
+      instant_action_this_turn = true;
+      "If you could do that, you wouldn't have built the prototype.";
+  }
+  print "Time passes.^";
+  if (noun%5 ~= 0) {
+      if (noun/5 > 0)
+          IncTime();
+  }
+  for (t=1 : t<noun/5 : t++)
+      IncTime();
+  if (~~deadflag)
+      if (noun%5 ~= 0)
+            print "Indeed you pause for slightly longer than you had planned,
+                 carefully resynchronizing yourself with the 
+                 five second turn increments.^";
+];
+
+[ WaitTurnsSub t;
+  if (noun == 0) {
+      instant_action_this_turn = true;
+      "That didn't take long.";  
+  }
+  print "Time passes.^";
+  if (noun < 0) {
+      instant_action_this_turn = true;
+      "If you could do that, you wouldn't have built the prototype.";
+  }
+  for (t=1 : t<noun : t++)
+      IncTime();
+];
+
+[ WaitUntilSub time_in_turns t;
+   time_in_turns = noun / 5 - my_time;
+   if (time_in_turns > FINAL_TIME - my_time)
+       time_in_turns = FINAL_TIME - my_time + 2;
+  if (time_in_turns == 0 && (noun%5 ==0)) {
+      instant_action_this_turn = true;
+      "That didn't take long.";   
+  }
+  if (time_in_turns < 0) {
+      instant_action_this_turn = true;
+      "If you could do that, you wouldn't have built the prototype.";
+  }
+  print "Time passes.^";
+  if (noun%5 ~= 0) {
+      if (time_in_turns > 0)
+          IncTime();
+  }
+  for (t=1 : t<time_in_turns : t++)
+      IncTime();
+
+  if (~~deadflag)
+      if (noun%5 ~= 0)
+            print "Indeed you pause for slightly longer than you had planned,
+                 carefully resynchronizing yourself with the 
+                 five second turn increments.^";
+];
+
+[ HoursMinsSecsWordToTime hour minute second word;
+  if (hour >= 24) return -1;
+  if (minute >= 60) return -1;
+  if (second >= 60) return -1;
+  if (hour > 4) return 18000;      ! this is to avoid integer overflow
+  if (word == 'pm') 
+      return 18000;
+
+  return (hour*60 + minute) * 60 + second;
+]; 
+    
+! based on the code from the DM4.
+! looks for a time in the format 2:39 or 4:17:18
+    
+[ TimeOfDay first_word second_word at length colons illegal_char digits hr mn se i;
+   first_word = NextWordStopped();
+   if (first_word == -1) 
+       return GPR_FAIL;
+   at = WordAddress(wn-1);
+   length = WordLength(wn-1);
+   for (i=0: i<length: i++) {
+       switch (at->i) {
+           ':': if (colons == 0 && digits>0 && i<length-1) {
+                    colons = 1;
+                    digits = 0;
+                }
+                else if (colons == 1 && digits==2 && i<length-1) {
+                    colons = 2;
+                    digits = 0;
+                }
+                else
+                    illegal_char = true;
+           '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 
+                digits = digits+1;
+                if (digits > 2)
+                    illegal_char = true;
+           default: illegal_char = true;
+       } 
+   }
+   if (length < 3 || length > 8 || illegal_char || colons == 0)
+        return GPR_FAIL;
+   for (i=0: at->i~=':': i++, hr=hr*10)
+       hr = hr + at->i - '0';
+   hr = hr/10;
+   mn = ((at->(i+1) - '0') * 10) + at->(i+2) - '0';
+   if (colons == 2) {
+       i = i+3;
+       se = ((at->(i+1) - '0') * 10) + at->(i+2) - '0';
+   }
+   second_word = NextWordStopped();
+   parsed_number = HoursMinsSecsWordToTime(hr, mn, se, second_word);
+   if (parsed_number == -1) return GPR_FAIL; if (second_word ~= 'pm' or 'am') wn--;
+   return GPR_NUMBER;
+];
+Extend 'wait'
+    * number                      -> WaitSeconds
+    * number 'seconds'            -> WaitSeconds
+    * number 'second'             -> WaitSeconds
+    * number 'turns'              -> WaitTurns
+    * number 'turn'               -> WaitTurns
+    * 'until' TimeOfDay           -> WaitUntil;
+    
+    
+[ ShoutSub t;
+    print "You shout loudly.^";
+    for (t=0 : t<time_travelled : t++) {
+        if ((former_self-->t notin limbo) && 
+            ((siren_start_time == UNKNOWN_) || (siren_start_time > my_time))) {
+            
+            d_paradox = true;
+            deadflag = 3;
+            Seperator();
+            print (Nearby) 0, "your former self hears the muffled sounds of your
+                   shouting.^^Something of an anticlimactic way to kill 
+                   so many millions of people...^"; 
+            print "^Time unravels...^";
+            Devours(my_time);                            
+            return true;
+        }
+    }
+    Put2D(dangerous_activity,time_travelled,my_time-EARLIEST_TIME,SHOUT_);
+                MaybeSing();
+    return true;
+];
+
+Extend only 'shout' replace
+    *                             -> Shout
+    * topic                       -> Shout;
+    
+Verb 'yell'
+    *                             -> Shout
+    * topic                       -> Shout;
+
+Verb 'tear'
+    * noun                        -> Attack
+    * 'up' noun                   -> Attack;
+
+Extend 'remove' first                                   ! so that 'remove battery' works
+    * multiinside                 -> Remove;
+
+[ HoldDownWithSub;
+    if (noun == alarm_button || noun == basement_button || noun == first_button ||
+        noun == second_button || noun == silver_button || noun == exit_button ) {
+        "The button is set into a vertical surface, 
+         making it impossible to hold it down with another object.";
+    }        
+    else
+        "It is not clear what that is supposed to accomplish.";
+];
+
+Extend 'hold' first                                   ! so that 'remove battery' works
+    * 'down' noun                 -> Push
+    * 'down' noun 'with' noun     -> HoldDownWith
+    * 'down' noun 'using' noun    -> HoldDownWith;
+  
+[ ChallengeSub;
+    instant_action_this_turn = true;
+    if (challenge)
+        "The challenge has already been initiated.";
+    if (first_turn) {
+        challenge = true;
+        siren_timeout = CHALLENGE_SIREN_TIMEOUT;
+        early_guard_time = CHALLENGE_EARLY_GUARD_TIME;
+        "The game is now in its most challenging form.
+         Three key elements have been changed to make success considerably
+         more difficult. This challenge is not
+         required for a successful completion of the game. It is just here
+         for those who, upon finishing, wish there was a little bit more.^
+         ^
+         If you do want to take up the challenge, then remember to initiate this
+         mode each time you begin play.";
+    }
+    else
+        "The challenge can only be initiated in the first turn.";
+];
+
+[ EndChallengeSub;
+    instant_action_this_turn = true;
+    challenge = false;
+    siren_timeout = DEFAULT_SIREN_TIMEOUT;
+    early_guard_time = EARLIEST_TIME;
+    "The game is now at its standard difficulty.";
+];
+
+Verb 'challenge'
+    *                             -> Challenge
+    * 'on'                        -> Challenge
+    * 'mode' 'on'                 -> Challenge
+    * 'off'                       -> EndChallenge
+    * 'mode' 'off'                -> EndChallenge;
+
+Verb 'start' 'begin' 'initiate'
+    * 'challenge'                 -> Challenge
+    * 'challenge' 'mode'          -> Challenge;
+
+Verb 'end'
+    * 'challenge'                 -> EndChallenge
+    * 'challenge' 'mode'          -> EndChallenge;
+    
+!============================================================================
+
diff --git a/lib b/lib
new file mode 160000 (submodule)
index 0000000..aec9e41
--- /dev/null
+++ b/lib
@@ -0,0 +1 @@
+Subproject commit aec9e4131b092ed33213b9891e1dc2b9574edf99