Initial import.
authornotzed@gmail.com <notzed@gmail.com@b8b59bfb-1aa4-4687-8f88-a62eeb14c21e>
Thu, 28 Feb 2013 10:33:46 +0000 (10:33 +0000)
committernotzed@gmail.com <notzed@gmail.com@b8b59bfb-1aa4-4687-8f88-a62eeb14c21e>
Thu, 28 Feb 2013 10:33:46 +0000 (10:33 +0000)
git-svn-id: file:///home/notzed/svn/duskz/trunk@2 b8b59bfb-1aa4-4687-8f88-a62eeb14c21e

99 files changed:
DuskCommon/COPYING [new file with mode: 0644]
DuskCommon/README [new file with mode: 0644]
DuskCommon/build.xml [new file with mode: 0644]
DuskCommon/nbproject/build-impl.xml [new file with mode: 0644]
DuskCommon/nbproject/genfiles.properties [new file with mode: 0644]
DuskCommon/nbproject/project.properties [new file with mode: 0644]
DuskCommon/nbproject/project.xml [new file with mode: 0644]
DuskCommon/src/duskz/protocol/MessageType.java [new file with mode: 0644]
DuskCommon/src/duskz/protocol/ServerMessage.java [new file with mode: 0644]
DuskCommon/src/duskz/protocol/TransactionItem.java [new file with mode: 0644]
DuskCommon/src/duskz/protocol/Wearing.java [new file with mode: 0644]
DuskCommon/src/duskz/util/Debug.java [new file with mode: 0644]
DuskCommon/src/duskz/util/Maths.java [new file with mode: 0644]
DuskServer/COPYING [new file with mode: 0644]
DuskServer/README [new file with mode: 0644]
DuskServer/build.xml [new file with mode: 0644]
DuskServer/manifest.mf [new file with mode: 0644]
DuskServer/nbproject/build-impl.xml [new file with mode: 0644]
DuskServer/nbproject/genfiles.properties [new file with mode: 0644]
DuskServer/nbproject/project.properties [new file with mode: 0644]
DuskServer/nbproject/project.xml [new file with mode: 0644]
DuskServer/src/duskz/io/Tiled.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Data.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Image.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Layer.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Map.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Object.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/ObjectFactory.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Objectgroup.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Properties.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Property.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Tile.java [new file with mode: 0644]
DuskServer/src/duskz/io/tiled/Tileset.java [new file with mode: 0644]
DuskServer/src/duskz/proto/Junk.java [new file with mode: 0644]
DuskServer/src/duskz/server/Battle.java [new file with mode: 0644]
DuskServer/src/duskz/server/Commands.java [new file with mode: 0644]
DuskServer/src/duskz/server/Condition.java [new file with mode: 0644]
DuskServer/src/duskz/server/Config.java [new file with mode: 0644]
DuskServer/src/duskz/server/Constants.java [new file with mode: 0644]
DuskServer/src/duskz/server/DuskEngine.java [new file with mode: 0644]
DuskServer/src/duskz/server/DuskServer.java [new file with mode: 0644]
DuskServer/src/duskz/server/Faction.java [new file with mode: 0644]
DuskServer/src/duskz/server/GiveItem.java [new file with mode: 0644]
DuskServer/src/duskz/server/ItemList.java [new file with mode: 0644]
DuskServer/src/duskz/server/Log.java [new file with mode: 0644]
DuskServer/src/duskz/server/RandomAccessString.java [new file with mode: 0644]
DuskServer/src/duskz/server/SaveThread.java [new file with mode: 0644]
DuskServer/src/duskz/server/Script.java [new file with mode: 0644]
DuskServer/src/duskz/server/ScriptManager.java [new file with mode: 0644]
DuskServer/src/duskz/server/SpellGroup.java [new file with mode: 0644]
DuskServer/src/duskz/server/TickThread.java [new file with mode: 0644]
DuskServer/src/duskz/server/TrackerThread.java [new file with mode: 0644]
DuskServer/src/duskz/server/Variable.java [new file with mode: 0644]
DuskServer/src/duskz/server/VariableSet.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Ability.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/DuskObject.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Equipment.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Item.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/LivingThing.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Merchant.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Mob.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/PlayerMerchant.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Prop.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/Sign.java [new file with mode: 0644]
DuskServer/src/duskz/server/entity/TileMap.java [new file with mode: 0644]
DuskZ/COPYING [new file with mode: 0644]
DuskZ/COPYING.GPLv2 [new file with mode: 0644]
DuskZ/README [new file with mode: 0644]
DuskZ/build.xml [new file with mode: 0644]
DuskZ/manifest.mf [new file with mode: 0644]
DuskZ/nbproject/build-impl.xml [new file with mode: 0644]
DuskZ/nbproject/configs/Run_as_WebStart.properties [new file with mode: 0644]
DuskZ/nbproject/configs/Run_in_Browser.properties [new file with mode: 0644]
DuskZ/nbproject/genfiles.properties [new file with mode: 0644]
DuskZ/nbproject/jfx-impl.xml [new file with mode: 0644]
DuskZ/nbproject/project.properties [new file with mode: 0644]
DuskZ/nbproject/project.xml [new file with mode: 0644]
DuskZ/src/duskz/client/Bookmarks.java [new file with mode: 0644]
DuskZ/src/duskz/client/ClientMap.java [new file with mode: 0644]
DuskZ/src/duskz/client/DataManager.java [new file with mode: 0644]
DuskZ/src/duskz/client/Direction.java [new file with mode: 0644]
DuskZ/src/duskz/client/Dusk.java [new file with mode: 0644]
DuskZ/src/duskz/client/Entity.java [new file with mode: 0644]
DuskZ/src/duskz/client/Equipment.java [new file with mode: 0644]
DuskZ/src/duskz/client/GUI.java [new file with mode: 0644]
DuskZ/src/duskz/client/Status.java [new file with mode: 0644]
DuskZ/src/duskz/client/TransactionItem.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/DataManagerFX.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/DuskFX.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/EquipmentPane.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/MainFrameFX.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/TransactionPane.java [new file with mode: 0644]
DuskZ/src/duskz/client/fx/style.css [new file with mode: 0644]
DuskZ/src/jfxtras/labs/animation/Timer.java [new file with mode: 0644]
DuskZ/src/jfxtras/labs/internal/scene/control/ListSpinner.css [new file with mode: 0644]
DuskZ/src/jfxtras/labs/internal/scene/control/behavior/ListSpinnerBehavior.java [new file with mode: 0644]
DuskZ/src/jfxtras/labs/internal/scene/control/skin/ListSpinnerCaspianSkin.java [new file with mode: 0644]
DuskZ/src/jfxtras/labs/scene/control/ListSpinner.java [new file with mode: 0644]
DuskZ/src/jfxtras/labs/scene/control/ListSpinnerIntegerList.java [new file with mode: 0644]

diff --git a/DuskCommon/COPYING b/DuskCommon/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  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
+this service 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.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+                     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
+convey 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 General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/DuskCommon/README b/DuskCommon/README
new file mode 100644 (file)
index 0000000..2df1b47
--- /dev/null
@@ -0,0 +1,32 @@
+
+README
+------
+This is a library containing some common utilities and classes betwen
+server and client.
+
+This is primarily classes and utilities for handling the client<>server
+protocol.
+
+LICENSE
+-------
+  DuskZ is free software, see COPYING for your rights.
+
+  Some files are under other compatible licenses.
+
+  Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+  Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+   DuskZ is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   DuskZ is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with DuskZ; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
\ No newline at end of file
diff --git a/DuskCommon/build.xml b/DuskCommon/build.xml
new file mode 100644 (file)
index 0000000..23edae7
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="DuskCommon" default="default" basedir=".">
+    <description>Builds, tests, and runs the project DuskCommon.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="DuskCommon-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/DuskCommon/nbproject/build-impl.xml b/DuskCommon/nbproject/build-impl.xml
new file mode 100644 (file)
index 0000000..625b5c6
--- /dev/null
@@ -0,0 +1,1411 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - test compilation
+  - test execution
+  - test debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="DuskCommon-impl">
+    <fail message="Please build using Ant 1.8.0 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.8.0"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <property name="javac.fork" value="${jdkBug6558476}"/>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <property name="copylibs.rebase" value="true"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+        <condition property="junit.available">
+            <or>
+                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+            </or>
+        </condition>
+        <condition property="testng.available">
+            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+        </condition>
+        <condition property="junit+testng.available">
+            <and>
+                <istrue value="${junit.available}"/>
+                <istrue value="${testng.available}"/>
+            </and>
+        </condition>
+        <condition else="testng" property="testng.mode" value="mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <condition else="" property="testng.debug.mode" value="-mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-init">
+        <condition else="false" property="nb.junit.batch" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <not>
+                    <isset property="test.method"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="nb.junit.single" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <isset property="test.method"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-init-test-properties">
+        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+        <property name="test.binarytestincludes" value=""/>
+        <property name="test.binaryexcludes" value=""/>
+    </target>
+    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+    <target if="${testng.available}" name="-init-macrodef-testng">
+        <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+                    <isset property="test.method"/>
+                </condition>
+                <union id="test.set">
+                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+                        <filename name="@{testincludes}"/>
+                    </fileset>
+                </union>
+                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+                <testng classfilesetref="test.set" failureProperty="tests.failed" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="DuskCommon" testname="TestNG tests" workingDir="${work.dir}">
+                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+                    <propertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </propertyset>
+                    <customize/>
+                </testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-test-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <echo>No tests executed.</echo>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+        <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <sequential>
+                <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${testng.available}" name="-init-macrodef-testng-debug">
+        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element name="customize2" optional="true"/>
+            <sequential>
+                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+                    <isset property="test.method"/>
+                </condition>
+                <condition else="-suitename DuskCommon -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                    <matches pattern=".*\.xml" string="@{testClass}"/>
+                </condition>
+                <delete dir="${build.test.results.dir}" quiet="true"/>
+                <mkdir dir="${build.test.results.dir}"/>
+                <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+                    <customize>
+                        <customize2/>
+                        <jvmarg value="-ea"/>
+                        <arg line="${testng.debug.mode}"/>
+                        <arg line="-d ${build.test.results.dir}"/>
+                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
+                        <arg line="${testng.cmd.args}"/>
+                    </customize>
+                </j2seproject3:debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element implicit="true" name="customize2" optional="true"/>
+            <sequential>
+                <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2/>
+                </j2seproject3:testng-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2>
+                        <syspropertyset>
+                            <propertyref prefix="test-sys-prop."/>
+                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                        </syspropertyset>
+                    </customize2>
+                </j2seproject3:testng-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+    <!--
+                pre NB7.2 profiling section; consider it deprecated
+            -->
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <!--
+                end of pre NB7.2 profiling section
+            -->
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version &quot;${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <attribute default="jvm" name="jvm"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <filtermapper>
+                            <replacestring from=" " to="%20"/>
+                        </filtermapper>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: DuskCommon was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <!--
+                pre NB7.2 profiler integration
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                end of pre NB72 profiling section
+            -->
+    <target if="netbeans.home" name="-profile-check">
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+        <startprofiler/>
+        <antcall target="run"/>
+    </target>
+    <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcall target="run-single"/>
+    </target>
+    <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+    <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <startprofiler/>
+        <antcall target="test-single"/>
+    </target>
+    <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcal target="run-test-with-main"/>
+    </target>
+    <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <startprofiler/>
+        <antcall target="run-applet"/>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+            <and>
+                <isset property="endorsed.classpath.cmd.line.arg"/>
+                <not>
+                    <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+            <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                TEST COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                TEST EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:test testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+    <!--
+                =======================
+                TEST DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: DuskCommon was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <and>
+                <not>
+                    <isset property="already.built.${call.subproject}"/>
+                </not>
+                <available file="${call.script}"/>
+            </and>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/DuskCommon/nbproject/genfiles.properties b/DuskCommon/nbproject/genfiles.properties
new file mode 100644 (file)
index 0000000..b7dd181
--- /dev/null
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=cb9774bc
+build.xml.script.CRC32=41ed8886
+build.xml.stylesheet.CRC32=28e38971@1.56.1.46
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=cb9774bc
+nbproject/build-impl.xml.script.CRC32=4cf1c99d
+nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46
diff --git a/DuskCommon/nbproject/project.properties b/DuskCommon/nbproject/project.properties
new file mode 100644 (file)
index 0000000..0f9dd09
--- /dev/null
@@ -0,0 +1,70 @@
+project.license=dusk
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processor.options=
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/DuskCommon.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+javac.test.processorpath=\
+    ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=true
+platform.active=default_platform
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/DuskCommon/nbproject/project.xml b/DuskCommon/nbproject/project.xml
new file mode 100644 (file)
index 0000000..dabe64d
--- /dev/null
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>DuskCommon</name>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+    </configuration>
+</project>
diff --git a/DuskCommon/src/duskz/protocol/MessageType.java b/DuskCommon/src/duskz/protocol/MessageType.java
new file mode 100644 (file)
index 0000000..fee4a92
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.protocol;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Type of message sent from server.
+ *
+ * @author notzed
+ */
+public enum MessageType {
+
+       // 0
+       Quit,
+       UpdateImages,
+       UpdateLocMap {
+
+               @Override
+               public ServerMessage decode(DataInputStream instream) throws IOException {
+                       return ServerMessage.MapMessage.decode(instream);
+               }               
+       },
+       Chat,
+       AddEntity,
+       // 5
+       UpdateStats,
+       UpdateItems,
+       UpdateEquipment,
+       UpdateInfo,
+       Halt,
+       // 10
+       UpdateActions,
+       LoadMusic,
+       PlayMusic,
+       Ping,
+       Proceed,
+       // 15
+       PlaySound,
+       RemoveEntity,
+       UpdateMerchant,
+       EditText,
+       ResizeMap,
+       // 20
+       ViewText,
+       ExitMerchant,
+       UpdateSell,
+       ColourChat,
+       MoveNorth,
+       // 25
+       MoveSouth,
+       MoveWest,
+       MoveEast,
+       UpdateRange,
+       SetFlag,
+       // 30
+       ClearFlags,
+       StartBattle,
+       UpdateBattle,
+       LogBattle,
+       // Above list is compatible with original dusk, new ones follow
+       // A bunch of login/setup related stuff
+       /**
+        * Choose race, response is
+        * code header
+        * race 0
+        * race 1
+        * ...
+        * .
+        */
+       ChooseRace,
+       /**
+        * Damage (or healing) to an entity.
+        * Encoded as:
+        * targetID
+        * +-damage
+        * newhp
+        * totalhp
+        * fromID
+        * how
+        * .
+        */
+       HitEntity,;
+
+       public static MessageType fromServer(int v) {
+               return values()[v];
+       }
+
+       public char code() {
+               return (char) ordinal();
+       }
+
+       /**
+        * Not implemented yet
+        * @param instream
+        * @return
+        * @throws IOException
+        * @deprecated
+        */
+       @Deprecated
+       public ServerMessage decode(DataInputStream instream) throws IOException {
+               return null;
+       }
+}
diff --git a/DuskCommon/src/duskz/protocol/ServerMessage.java b/DuskCommon/src/duskz/protocol/ServerMessage.java
new file mode 100644 (file)
index 0000000..a133fd2
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.protocol;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Message from server to client
+ *
+ * @author notzed
+ */
+public abstract class ServerMessage {
+
+       final MessageType type;
+
+       public ServerMessage(MessageType type) {
+               this.type = type;
+       }
+
+       public abstract void send(DataOutputStream ostream) throws IOException;
+
+       public static ServerMessage stringMessage(String s) {
+               return new StringMessage(s);
+       }
+
+       public static ServerMessage stringMessage(MessageType type, String data) {
+               return new StringMessage(type, data);
+       }
+
+       public static ServerMessage mapMessage(int locx, int locy, short[] map) {
+               return new MapMessage(locx, locy, map);
+       }
+
+       public static ServerMessage fromServer(DataInputStream instream) throws IOException {
+               int typec = instream.readByte();
+
+               MessageType type = MessageType.values()[typec];
+               // TODO: more protocol, length?  how?
+
+               return type.decode(instream);
+       }
+
+       public static class StringMessage extends ServerMessage {
+
+               final String data;
+
+               public StringMessage(String data) {
+                       super(null);
+                       this.data = data;
+               }
+
+               private StringMessage(MessageType type, String data) {
+                       super(type);
+                       this.data = data;
+               }
+
+               @Override
+               public void send(DataOutputStream ostream) throws IOException {
+                       if (type != null)
+                               ostream.writeByte(type.code());
+                       ostream.writeBytes(data);
+               }
+
+               @Override
+               public String toString() {
+                       return data;
+               }
+       }
+
+       public static class MapMessage extends ServerMessage {
+
+               public int x;
+               public int y;
+               public short[] map;
+
+               public MapMessage(int locx, int locy, short[] map) {
+                       super(MessageType.UpdateLocMap);
+                       this.x = locx;
+                       this.y = locy;
+                       this.map = map;
+               }
+
+               public static MapMessage decode(DataInputStream instream) throws IOException {
+                       int x = instream.readShort();
+                       int y = instream.readShort();
+                       int length = instream.readInt();
+                       short[] map = new short[length];
+                       for (int i = 0; i < length; i++) {
+                               map[i] = instream.readShort();
+                       }
+                       return new MapMessage(x, y, map);
+               }
+
+               @Override
+               public void send(DataOutputStream ostream) throws IOException {
+                       ostream.writeByte(type.code());
+                       ostream.writeShort(x);
+                       ostream.writeShort(y);
+                       ostream.writeInt(map.length);
+                       for (int i = 0; i < map.length; i++)
+                               ostream.writeShort(map[i]);
+               }
+       }
+
+       public static class EntityMessage extends ServerMessage {
+
+               public long id;
+               public String name;
+               public byte entityType;
+               public short x;
+               public short y;
+               public short image;
+               public short imageStep;
+
+               public EntityMessage(MessageType type, long id, String name, byte entityType, short x, short y, short image, short imageStep) {
+                       super(type);
+                       this.id = id;
+                       this.name = name;
+                       this.entityType = entityType;
+                       this.x = x;
+                       this.y = y;
+                       this.image = image;
+                       this.imageStep = imageStep;
+
+                       System.out.printf("create entity message: %d '%s' %d %dx%d image %d %d\n",
+                                       id, name, entityType, x, y, image, imageStep);
+               }
+
+               public static EntityMessage decode(MessageType type, DataInputStream instream) throws IOException {
+                       long id = instream.readLong();
+                       String name = instream.readUTF();
+                       byte entityType = instream.readByte();
+                       short x = instream.readShort();
+                       short y = instream.readShort();
+                       short image = instream.readShort();
+                       short imageStep = instream.readShort();
+
+                       return new EntityMessage(type, id, name, entityType, x, y, image, imageStep);
+               }
+
+               @Override
+               public void send(DataOutputStream ostream) throws IOException {
+                       ostream.writeByte(type.code());
+                       ostream.writeLong(id);
+                       ostream.writeUTF(name);
+                       ostream.writeByte(entityType);
+                       ostream.writeShort(x);
+                       ostream.writeShort(y);
+                       ostream.writeShort(image);
+                       ostream.writeShort(imageStep);
+               }
+       }
+
+       /**
+        * Main player stats
+        */
+       public static class StatsMessage extends ServerMessage {
+
+               public long cash;
+               public int exp;
+               public int stre, strebonus;
+               public int inte, intebonus;
+               public int dext, dextbonus;
+               public int cons, consbonus;
+               public int wisd, wisdbonus;
+               public int damm, dammbonus;
+               public int ac, acbonus;
+
+               public StatsMessage(MessageType type, long cash, int exp, int stre, int strebonus,
+                               int inte, int intebonus, int dext, int dextbonus, int cons, int consbonus,
+                               int wisd, int wisdbonus, int damm, int dammbonus, int ac, int acbonus) {
+                       super(type);
+                       this.cash = cash;
+                       this.exp = exp;
+                       this.stre = stre;
+                       this.strebonus = strebonus;
+                       this.inte = inte;
+                       this.intebonus = intebonus;
+                       this.dext = dext;
+                       this.dextbonus = dextbonus;
+                       this.cons = cons;
+                       this.consbonus = consbonus;
+                       this.wisd = wisd;
+                       this.wisdbonus = wisdbonus;
+                       this.damm = damm;
+                       this.dammbonus = dammbonus;
+                       this.ac = ac;
+                       this.acbonus = acbonus;
+               }
+
+               public static StatsMessage decode(MessageType type, DataInputStream instream) throws IOException {
+                       long cash = instream.readLong();
+                       int exp = instream.readInt();
+                       int stre = instream.readInt();
+                       int strebonus = instream.readInt();
+                       int inte = instream.readInt();
+                       int intebonus = instream.readInt();
+                       int dext = instream.readInt();
+                       int dextbonus = instream.readInt();
+                       int cons = instream.readInt();
+                       int consbonus = instream.readInt();
+                       int wisd = instream.readInt();
+                       int wisdbonus = instream.readInt();
+                       int damm = instream.readInt();
+                       int dammbonus = instream.readInt();
+                       int ac = instream.readInt();
+                       int acbonus = instream.readInt();
+
+                       return new StatsMessage(type, cash, exp,
+                                       stre, strebonus,
+                                       inte, intebonus,
+                                       dext, dextbonus,
+                                       cons, consbonus,
+                                       wisd, wisdbonus,
+                                       damm, dammbonus,
+                                       ac, acbonus);
+               }
+
+               @Override
+               public void send(DataOutputStream ostream) throws IOException {
+                       ostream.writeByte(type.code());
+                       ostream.writeLong(cash);
+                       ostream.writeInt(exp);
+                       ostream.writeInt(stre);
+                       ostream.writeInt(strebonus);
+                       ostream.writeInt(inte);
+                       ostream.writeInt(intebonus);
+                       ostream.writeInt(dext);
+                       ostream.writeInt(dextbonus);
+                       ostream.writeInt(cons);
+                       ostream.writeInt(consbonus);
+                       ostream.writeInt(wisd);
+                       ostream.writeInt(wisdbonus);
+                       ostream.writeInt(damm);
+                       ostream.writeInt(dammbonus);
+                       ostream.writeInt(ac);
+                       ostream.writeInt(acbonus);
+               }
+       }
+
+       /**
+        * Other player stats?
+        * All together or separate?
+        * UpdateSkills
+        * UpdateConditions?
+        */
+       /*
+        strResult += "-Affected by-\n";
+        for (Condition cond : conditions) {
+        if (cond.display) {
+        strResult += cond.name + "\n";
+        }
+        }
+        strResult += "-Skills-\n";
+        for (Ability skill : skillMap.values()) {
+        strResult += skill.name + ": " + skill.getAbility() + "\n";
+        }
+        strResult += "-Spells-\n";
+        for (Ability spell : spellMap.values()) {
+        grpStore = game.getSpellGroup(spell.name);
+        if (grpStore != null) {
+        strResult += spell.name + ": " + spell.getAbility() + "\n";
+        strResult += grpStore.spellList(spell.getAbility());
+        }
+        }
+        if (master != null) {
+        strResult += "\nFollowing: " + master.name + "\n";
+        }*/
+       public static class ItemsMessage extends ServerMessage {
+
+               List<TransactionItem> items;
+
+               public ItemsMessage(MessageType type, List<TransactionItem> items) {
+                       super(type);
+                       this.items = items;
+               }
+
+               public static ItemsMessage decode(MessageType type, DataInputStream instream) throws IOException {
+                       List<TransactionItem> items = new ArrayList<>();
+
+                       int count = instream.readShort();
+                       for (int i = 0; i < count; i++) {
+                               TransactionItem item = new TransactionItem();
+
+                               item.name = instream.readUTF();
+                               item.count = instream.readInt();
+                               item.cost = instream.readInt();
+                               item.units = instream.readUTF();
+                       }
+
+                       return new ItemsMessage(type, items);
+               }
+
+               @Override
+               public void send(DataOutputStream ostream) throws IOException {
+                       ostream.writeByte(type.code());
+                       ostream.writeShort(items.size());
+                       for (TransactionItem item : items) {
+                               ostream.writeUTF(item.getName());
+                               ostream.writeInt(item.getCount());
+                               ostream.writeInt(item.getCost());
+                               ostream.writeUTF(item.getUnits());
+                       }
+               }
+       }
+}
diff --git a/DuskCommon/src/duskz/protocol/TransactionItem.java b/DuskCommon/src/duskz/protocol/TransactionItem.java
new file mode 100644 (file)
index 0000000..cead913
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.protocol;
+
+/**
+ * Represents a transaction item (buy/sell) for server protocol.
+ * @author notzed
+ */
+public class TransactionItem implements Comparable<TransactionItem>{
+
+       public String name;
+       public int count;
+       public int cost;
+       public String units;
+
+       public TransactionItem() {
+       }
+
+       
+       public TransactionItem(String name, int count, int cost, String units) {
+               this.name = name;
+               this.count = count;
+               this.cost = cost;
+               this.units = units;
+       }
+       
+       public String getName() {
+               return name;
+       }
+
+       public int getCount() {
+               return count;
+       }
+
+       public int getCost() {
+               return cost;
+       }
+
+       public String getUnits() {
+               return units;
+       }
+               
+       @Override
+       public String toString() {
+               return cost + ") " + name + "[" + count + "]";
+       }
+       
+       @Override
+       public int compareTo(TransactionItem t) {
+               return name.compareTo(t.name);
+       }
+}
diff --git a/DuskCommon/src/duskz/protocol/Wearing.java b/DuskCommon/src/duskz/protocol/Wearing.java
new file mode 100644 (file)
index 0000000..ccd254e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.protocol;
+
+/**
+ * Constants for wearing locations.
+ * @author notzed
+ */
+public interface Wearing {
+
+       public static final int WIELD = 0;
+       public static final int ARMS = 1;
+       public static final int LEGS = 2;
+       public static final int TORSO = 3;
+       public static final int WAIST = 4;
+       public static final int NECK = 5;
+       public static final int SKULL = 6;
+       public static final int EYES = 7;
+       public static final int HANDS = 8;
+       public static final int WEARING_COUNT = 9;
+       public static final String[] titles = {
+               "Wielded", "Arms", "Legs", "Torso", "Waist", "Neck", "Skull", "Eyes", "Hands"
+       };
+       /**
+        * Field names as on the server
+        */
+       public static final String[] names = {
+               "wielded", "arms", "legs", "torso", "waist", "neck", "skull", "eyes", "hands"
+       };
+}
diff --git a/DuskCommon/src/duskz/util/Debug.java b/DuskCommon/src/duskz/util/Debug.java
new file mode 100644 (file)
index 0000000..1bacb85
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.util;
+
+/**
+ * Debugging utilities.
+ * @author notzed
+ */
+public class Debug {
+
+       /**
+        * Print a stack trace of the current position to stderr.
+        */
+       public static void stackTrace() {
+               try {
+                       throw new Exception();
+               } catch (Exception e) {
+                       System.out.println("The following stacktrace is only for debugging and is not an error");
+                       e.printStackTrace();
+               }
+       }
+}
diff --git a/DuskCommon/src/duskz/util/Maths.java b/DuskCommon/src/duskz/util/Maths.java
new file mode 100644 (file)
index 0000000..9bb6a3e
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.util;
+
+/**
+ * Some maths utilities.
+ *
+ * @author notzed
+ */
+public class Maths {
+
+       /**
+        * Clamp an integer to (l,u) inclusive.
+        *
+        * @param v
+        * @param l
+        * @param u
+        * @return
+        */
+       public static int clamp(int v, int l, int u) {
+               v = Math.max(v, l);
+               return Math.min(v, u);
+       }
+}
diff --git a/DuskServer/COPYING b/DuskServer/COPYING
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  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
+this service 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.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+                     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
+convey 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 General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/DuskServer/README b/DuskServer/README
new file mode 100644 (file)
index 0000000..658caf2
--- /dev/null
@@ -0,0 +1,44 @@
+
+README
+------
+This is the server implementation of DuskZ.  A client is required
+to access the game.
+
+It is a fork and major overhaul of the Dusk 2.7.3 source code, released
+circa 2000.
+
+This is currently in an alpha state and in very active development.
+
+ ... to be completed ...
+
+INSTALLATION
+------------
+ ... to be completed ...
+
+RUNNING
+-------
+ ... to be completed ...
+
+LICENSE
+-------
+  DuskZ is free software, see COPYING for your rights.
+
+  Some files are under other compatible licenses.
+
+  Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+  Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+   DuskZ is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+   DuskZ is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+   You should have received a copy of the GNU General Public License
+   along with DuskZ; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
\ No newline at end of file
diff --git a/DuskServer/build.xml b/DuskServer/build.xml
new file mode 100644 (file)
index 0000000..c74d44f
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- You may freely edit this file. See commented blocks below for -->
+<!-- some examples of how to customize the build. -->
+<!-- (If you delete it and reopen the project it will be recreated.) -->
+<!-- By default, only the Clean and Build commands use this build script. -->
+<!-- Commands such as Run, Debug, and Test only use this build script if -->
+<!-- the Compile on Save feature is turned off for the project. -->
+<!-- You can turn off the Compile on Save (or Deploy on Save) setting -->
+<!-- in the project's Project Properties dialog box.-->
+<project name="DuskServer" default="default" basedir=".">
+    <description>Builds, tests, and runs the project DuskServer.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. They are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-single:       called before javac compilation of single file
+      -post-compile-single:      called after javac compilation of single file
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-compile-test-single:  called before javac compilation of single JUnit test
+      -post-compile-test-single: called after javac compilation of single JUunit test
+      -pre-jar:                  called before JAR building
+      -post-jar:                 called after JAR building
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting an obfuscator after compilation could look like this:
+
+        <target name="-post-compile">
+            <obfuscate>
+                <fileset dir="${build.classes.dir}"/>
+            </obfuscate>
+        </target>
+
+    For list of available properties check the imported 
+    nbproject/build-impl.xml file. 
+
+
+    Another way to customize the build is by overriding existing main targets.
+    The targets of interest are: 
+
+      -init-macrodef-javac:     defines macro for javac compilation
+      -init-macrodef-junit:     defines macro for junit execution
+      -init-macrodef-debug:     defines macro for class debugging
+      -init-macrodef-java:      defines macro for class execution
+      -do-jar-with-manifest:    JAR building (if you are using a manifest)
+      -do-jar-without-manifest: JAR building (if you are not using a manifest)
+      run:                      execution of project 
+      -javadoc-build:           Javadoc generation
+      test-report:              JUnit report generation
+
+    An example of overriding the target for project execution could look like this:
+
+        <target name="run" depends="DuskServer-impl.jar">
+            <exec dir="bin" executable="launcher.exe">
+                <arg file="${dist.jar}"/>
+            </exec>
+        </target>
+
+    Notice that the overridden target depends on the jar target and not only on 
+    the compile target as the regular run target does. Again, for a list of available 
+    properties which you can use, check the target you are overriding in the
+    nbproject/build-impl.xml file. 
+
+    -->
+</project>
diff --git a/DuskServer/manifest.mf b/DuskServer/manifest.mf
new file mode 100644 (file)
index 0000000..328e8e5
--- /dev/null
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/DuskServer/nbproject/build-impl.xml b/DuskServer/nbproject/build-impl.xml
new file mode 100644 (file)
index 0000000..d26c819
--- /dev/null
@@ -0,0 +1,1425 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - test compilation
+  - test execution
+  - test debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="DuskServer-impl">
+    <fail message="Please build using Ant 1.8.0 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.8.0"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <condition else="false" property="jdkBug6558476">
+            <and>
+                <matches pattern="1\.[56]" string="${java.specification.version}"/>
+                <not>
+                    <os family="unix"/>
+                </not>
+            </and>
+        </condition>
+        <property name="javac.fork" value="${jdkBug6558476}"/>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <property name="copylibs.rebase" value="true"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+        <condition property="junit.available">
+            <or>
+                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+            </or>
+        </condition>
+        <condition property="testng.available">
+            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+        </condition>
+        <condition property="junit+testng.available">
+            <and>
+                <istrue value="${junit.available}"/>
+                <istrue value="${testng.available}"/>
+            </and>
+        </condition>
+        <condition else="testng" property="testng.mode" value="mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <condition else="" property="testng.debug.mode" value="-mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" fork="${javac.fork}" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-init">
+        <condition else="false" property="nb.junit.batch" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <not>
+                    <isset property="test.method"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="nb.junit.single" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <isset property="test.method"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-init-test-properties">
+        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+        <property name="test.binarytestincludes" value=""/>
+        <property name="test.binaryexcludes" value=""/>
+    </target>
+    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+    <target if="${testng.available}" name="-init-macrodef-testng">
+        <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+                    <isset property="test.method"/>
+                </condition>
+                <union id="test.set">
+                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+                        <filename name="@{testincludes}"/>
+                    </fileset>
+                </union>
+                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+                <testng classfilesetref="test.set" failureProperty="tests.failed" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="DuskServer" testname="TestNG tests" workingDir="${work.dir}">
+                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+                    <propertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </propertyset>
+                    <customize/>
+                </testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-test-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <echo>No tests executed.</echo>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+        <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <sequential>
+                <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${testng.available}" name="-init-macrodef-testng-debug">
+        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element name="customize2" optional="true"/>
+            <sequential>
+                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+                    <isset property="test.method"/>
+                </condition>
+                <condition else="-suitename DuskServer -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                    <matches pattern=".*\.xml" string="@{testClass}"/>
+                </condition>
+                <delete dir="${build.test.results.dir}" quiet="true"/>
+                <mkdir dir="${build.test.results.dir}"/>
+                <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+                    <customize>
+                        <customize2/>
+                        <jvmarg value="-ea"/>
+                        <arg line="${testng.debug.mode}"/>
+                        <arg line="-d ${build.test.results.dir}"/>
+                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
+                        <arg line="${testng.cmd.args}"/>
+                    </customize>
+                </j2seproject3:debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element implicit="true" name="customize2" optional="true"/>
+            <sequential>
+                <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2/>
+                </j2seproject3:testng-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2>
+                        <syspropertyset>
+                            <propertyref prefix="test-sys-prop."/>
+                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                        </syspropertyset>
+                    </customize2>
+                </j2seproject3:testng-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+    <!--
+                pre NB7.2 profiling section; consider it deprecated
+            -->
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <!--
+                end of pre NB7.2 profiling section
+            -->
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version &quot;${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <attribute default="jvm" name="jvm"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <filtermapper>
+                            <replacestring from=" " to="%20"/>
+                        </filtermapper>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: DuskServer was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-jar.properties}"/>
+            <param location="${project.DuskCommon}" name="call.subproject"/>
+            <param location="${project.DuskCommon}/build.xml" name="call.script"/>
+            <param name="call.target" value="jar"/>
+            <param name="transfer.built-jar.properties" value="${built-jar.properties}"/>
+        </antcall>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo level="info">java -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">java -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
+    <target name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <!--
+                pre NB7.2 profiler integration
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                end of pre NB72 profiling section
+            -->
+    <target if="netbeans.home" name="-profile-check">
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    <target depends="-profile-check,-profile-pre72" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+        <startprofiler/>
+        <antcall target="run"/>
+    </target>
+    <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcall target="run-single"/>
+    </target>
+    <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+    <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <startprofiler/>
+        <antcall target="test-single"/>
+    </target>
+    <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcal target="run-test-with-main"/>
+    </target>
+    <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <startprofiler/>
+        <antcall target="run-applet"/>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+            <and>
+                <isset property="endorsed.classpath.cmd.line.arg"/>
+                <not>
+                    <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+            <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                TEST COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                TEST EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:test testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+    <!--
+                =======================
+                TEST DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: DuskServer was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-clean.properties}"/>
+            <param location="${project.DuskCommon}" name="call.subproject"/>
+            <param location="${project.DuskCommon}/build.xml" name="call.script"/>
+            <param name="call.target" value="clean"/>
+            <param name="transfer.built-clean.properties" value="${built-clean.properties}"/>
+        </antcall>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <and>
+                <not>
+                    <isset property="already.built.${call.subproject}"/>
+                </not>
+                <available file="${call.script}"/>
+            </and>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/DuskServer/nbproject/genfiles.properties b/DuskServer/nbproject/genfiles.properties
new file mode 100644 (file)
index 0000000..0cb0205
--- /dev/null
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=d4396c02
+build.xml.script.CRC32=b70baa11
+build.xml.stylesheet.CRC32=28e38971@1.56.1.46
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=d4396c02
+nbproject/build-impl.xml.script.CRC32=6bdc7120
+nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46
diff --git a/DuskServer/nbproject/project.properties b/DuskServer/nbproject/project.properties
new file mode 100644 (file)
index 0000000..347a74d
--- /dev/null
@@ -0,0 +1,77 @@
+application.title=DuskServer
+application.vendor=Michael Zucchi
+endorsed.classpath=
+project.license=dusk
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/DuskServer.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+excludes=
+includes=**
+jar.compress=false
+javac.classpath=\
+    ${reference.DuskCommon.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+javac.test.processorpath=\
+    ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+main.class=duskz.server.DuskServer
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=default_platform
+project.DuskCommon=../DuskCommon
+reference.DuskCommon.jar=${project.DuskCommon}/dist/DuskCommon.jar
+run.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+# Space-separated list of JVM arguments used when running the project.
+# You may also define separate properties like run-sys-prop.name=value instead of -Dname=value.
+# To set system properties for unit tests define test-sys-prop.name=value:
+run.jvmargs=
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/DuskServer/nbproject/project.xml b/DuskServer/nbproject/project.xml
new file mode 100644 (file)
index 0000000..030b1fb
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>DuskServer</name>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
+            <reference>
+                <foreign-project>DuskCommon</foreign-project>
+                <artifact-type>jar</artifact-type>
+                <script>build.xml</script>
+                <target>jar</target>
+                <clean-target>clean</clean-target>
+                <id>jar</id>
+            </reference>
+        </references>
+    </configuration>
+</project>
diff --git a/DuskServer/src/duskz/io/Tiled.java b/DuskServer/src/duskz/io/Tiled.java
new file mode 100644 (file)
index 0000000..b8aeda1
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.io;
+
+import duskz.server.entity.TileMap;
+import duskz.io.tiled.Data;
+import duskz.io.tiled.Image;
+import duskz.io.tiled.Layer;
+import duskz.io.tiled.Map;
+import duskz.io.tiled.Property;
+import duskz.io.tiled.Tile;
+import duskz.io.tiled.Tileset;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import java.util.jar.Manifest;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.MemoryCacheImageInputStream;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+
+/**
+ * Tiled loader/converter.  This is only experimental at this stage.
+ *
+ * @author notzed
+ */
+public class Tiled {
+
+       static byte[] map64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(Charset.forName("US-ASCII"));
+       static byte[] unmap64 = new byte[256];
+
+       static {
+               for (int i = 0; i < 256; i++)
+                       unmap64[i] = -1;
+               for (int i = 0; i < 64; i++) {
+                       unmap64[map64[i]] = (byte) i;
+               }
+       }
+       // gzip and base64 result
+
+       static String encodeArray(byte[] data) throws IOException {
+               ByteArrayOutputStream os = new ByteArrayOutputStream();
+               GZIPOutputStream gz = new GZIPOutputStream(os);
+
+               gz.write(data);
+               gz.close();
+               return encodeBytes(os.toByteArray());
+       }
+
+       static InputStream decodeArray(String s) throws IOException {
+               ByteArrayInputStream is = new ByteArrayInputStream(decodeBytes(s));
+               GZIPInputStream gz = new GZIPInputStream(is);
+
+               return gz;
+       }
+
+       static int getCode(StringReader sr) throws IOException {
+               int v;
+
+               do {
+                       v = sr.read();
+                       if (v == -1)
+                               return -1;
+                       if (v == '=')
+                               return -1;
+                       v = unmap64[v];
+               } while (v == -1);
+               return v;
+       }
+
+       static byte[] decodeBytes(String s) throws IOException {
+               ByteBuffer dec = ByteBuffer.allocate(s.length());
+               StringReader sr = new StringReader(s);
+               int a, b, c, d;
+               do {
+                       a = getCode(sr);
+                       b = getCode(sr);
+                       c = getCode(sr);
+                       d = getCode(sr);
+
+                       if (a == -1) {
+                               // Truncated input
+                       } else if (b == -1) {
+                               // Truncated input
+                       } else if (c == -1) {
+                               // one encoded value
+                               dec.put((byte) ((a << 2) | (b >> 4)));
+                       } else if (d == -1) {
+                               // 2 encoded valus
+                               dec.put((byte) ((a << 2) | (b >> 4)));
+                               dec.put((byte) ((b << 4) | (c >> 2)));
+                       } else {
+                               dec.put((byte) ((a << 2) | (b >> 4)));
+                               dec.put((byte) ((b << 4) | (c >> 2)));
+                               dec.put((byte) ((c << 6) | d));
+                       }
+               } while (d != -1);
+
+               return Arrays.copyOf(dec.array(), dec.position());
+       }
+
+       static String encodeBytes(byte[] bytes) {
+               // Convert to base64
+               ByteBuffer enc = ByteBuffer.allocate(bytes.length * 4);
+               int i = 0;
+               int line = 0;
+               while (i < bytes.length) {
+                       int a = bytes[i++];
+                       int b = 0;
+                       int c = 0;
+                       int count = 2;
+
+                       if (i < bytes.length) {
+                               b = bytes[i++];
+                               count = 3;
+                       }
+                       if (i < bytes.length) {
+                               c = bytes[i++];
+                               count = 4;
+                       }
+
+                       enc.put(map64[(a >> 2) & 63]);
+                       enc.put(map64[((a << 4) & 0x30) | ((b >> 4) & 15)]);
+                       if (count > 2)
+                               enc.put(map64[((b << 2) & 0x3c) | ((c >> 6) & 3)]);
+                       else
+                               enc.put((byte) '=');
+                       if (count > 3)
+                               enc.put(map64[c & 63]);
+                       else
+                               enc.put((byte) '=');
+
+                       line += 4;
+                       if (line >= 72) {
+                               enc.put((byte) 10);
+                               line = 0;
+                       }
+               }
+               return new String(enc.array(), 0, enc.position(), Charset.forName("us-ascii"));
+       }
+
+       static String encodeImage(BufferedImage image) throws IOException {
+               ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+               ImageIO.write(image, "png", os);
+               os.close();
+               return encodeBytes(os.toByteArray());
+       }
+
+       static BufferedImage decodeImage(String enc) throws IOException {
+               byte[] data = decodeBytes(enc);
+               InputStream is = new ByteArrayInputStream(data);
+
+               return ImageIO.read(is);
+       }
+
+       static void testexport() throws IOException {
+               File path = new File("/home/notzed/src/DuskRPG/DuskFiles/Dusk2.7.3/shortmap");
+
+               TileMap map = TileMap.loadMap(path, TileMap.FORMAT_SHORT);
+               int width = map.getCols();
+               int height = map.getRows();
+               int len = width * height;
+
+
+               System.out.println("Map size: " + width + "," + height);
+
+               duskz.io.tiled.Map tmap = new duskz.io.tiled.Map();
+
+               tmap.setWidth(width);
+               tmap.setHeight(height);
+               tmap.setOrientation("orthogonal");
+               tmap.setVersion("1.0");
+               tmap.setTilewidth(32);
+               tmap.setTileheight(32);
+
+               Tileset tset = new Tileset();
+               tmap.getTileset().add(tset);
+
+               tset.setTileheight(32);
+               tset.setTilewidth(32);
+               tset.setFirstgid(0);
+               tset.setName("dusk-map");
+
+               // Add tile set
+               BufferedImage tiles = ImageIO.read(new File("/home/notzed/src/DuskRPG/DuskFiles/Dusk2.7.3/www/rc/somedusk/images/map.png"));
+               int tileWidth = 32;
+               int tileHeight = 32;
+               int imageWidth = tiles.getWidth();
+               for (int x = 0; x * tileWidth < imageWidth; x++) {
+                       BufferedImage tile = tiles.getSubimage(x * tileWidth, 0, tileWidth, tileHeight);
+
+                       Image timage = new Image();
+                       Data idata = new Data();
+
+                       idata.setEncoding("base64");
+                       idata.setvalue(encodeImage(tile));
+                       timage.setData(idata);
+                       timage.setFormat("png");
+
+                       Tile ttile = new Tile();
+                       ttile.setId(x);
+                       ttile.setImage(timage);
+
+                       tset.getTile().add(ttile);
+               }
+
+               // Add layer
+               Layer layer = new Layer();
+
+               tmap.getLayerOrObjectgroup().add(layer);
+
+               layer.setName("base");
+               layer.setVisible(1);
+               layer.setOpacity(1);
+               layer.setWidth(map.getCols());
+               layer.setHeight(map.getRows());
+
+               Data d = new Data();
+
+               layer.setData(d);
+
+               d.setCompression("gzip");
+               d.setEncoding("base64");
+
+               // First convert to ints
+               ByteBuffer bb = ByteBuffer.allocate(len * 4).order(ByteOrder.LITTLE_ENDIAN);
+
+               for (int y = 0; y < height; y++) {
+                       for (int x = 0; x < width; x++) {
+                               bb.putInt(map.getTile(x, y));
+                       }
+               }
+               bb.rewind();
+
+               d.setvalue(encodeArray(bb.array()));
+               //d.setvalue("dummy");
+
+               try {
+                       JAXBContext jc = JAXBContext.newInstance(Map.class);
+                       //Unmarshaller u = jc.createUnmarshaller();
+                       //Object element = u.unmarshal(new File("foo.xml"));
+                       Marshaller m = jc.createMarshaller();
+
+                       m.setProperty("jaxb.formatted.output", true);
+
+
+                       m.marshal(tmap, new File("/home/notzed/tiled-test.tmx"));
+
+               } catch (JAXBException ex) {
+                       Logger.getLogger(Tiled.class.getName()).log(Level.SEVERE, null, ex);
+               }
+               System.out.println("done");
+
+       }
+
+       static class TileInfo {
+
+               int id;
+               // Script names
+               String move;
+               String see;
+               String action;
+       }
+
+       static void testimport(File src, File dst) throws IOException {
+               try {
+                       JAXBContext jc = JAXBContext.newInstance(Map.class);
+                       Unmarshaller u = jc.createUnmarshaller();
+                       Map tmap = (Map) u.unmarshal(src);
+
+                       System.out.println("Loaded map size: " + tmap.getWidth() + "x" + tmap.getHeight());
+
+                       Manifest man = new Manifest();
+
+                       List<TileInfo> tileInfo = new ArrayList<>();
+                       int tid = 0;
+
+                       // Create manifest entires for tileset
+                       if (true) {
+                               int setid = 0;
+
+                               Attributes a = new Attributes();
+
+                               for (Tileset ts : tmap.getTileset()) {
+                                       int gid0 = ts.getFirstgid();
+
+                                       if (ts.getSource() != null) {
+                                               URI uri = src.toURI().resolve(ts.getSource());
+
+                                               ts = (Tileset) u.unmarshal(new File(uri));
+                                       }
+                                       if (!ts.getTile().isEmpty()) {
+                                               Tile tt = ts.getTile().get(0);
+                                               BufferedImage image = decodeImage(tt.getImage().getData().getvalue());
+
+                                               int twidth = image.getWidth();
+                                               int theight = image.getHeight();
+
+                                               a.putValue(setid + "_name", ts.getName());
+                                               a.putValue(setid + "_gid", String.valueOf(gid0));
+                                               a.putValue(setid + "_count", String.valueOf(ts.getTile().size()));
+                                               a.putValue(setid + "_source", "tiles/tiles_" + gid0 + ".png");
+                                               a.putValue(setid + "_width", String.valueOf(twidth));
+                                               a.putValue(setid + "_height", String.valueOf(theight));
+                                               setid++;
+
+                                               tid = 0;
+                                               // Add itle info
+                                               for (Tile ttile : ts.getTile()) {
+                                                       TileInfo ti = new TileInfo();
+
+                                                       // assume tid.id == tile id?
+                                                       if (tid != ttile.getId()) {
+                                                               System.out.println("shit tile id mismatch: " + tid + "!= " + ttile.getId());
+                                                       }
+                                                       ti.id = gid0 + tid;
+                                                       tid++;
+
+                                                       if (ttile.getProperties() != null) {
+                                                               for (Property p : ttile.getProperties().getProperty()) {
+                                                                       switch (p.getName()) {
+                                                                               case "move":
+                                                                                       ti.move = p.getValue();
+                                                                                       break;
+                                                                               case "see":
+                                                                                       ti.see = p.getValue();
+                                                                                       break;
+                                                                               case "action":
+                                                                                       ti.action = p.getValue();
+                                                                                       break;
+                                                                       }
+                                                               }
+                                                       }
+                                                       if (ti.move != null && ti.see == null) {
+                                                               ti.see = ti.move;
+                                                       }
+                                                       tileInfo.add(ti);
+                                               }
+
+                                       }
+
+                               }
+                               a.putValue("count", String.valueOf(setid));
+                               man.getEntries().put("tilesets", a);
+                       }
+
+                       JarOutputStream jos = new JarOutputStream(new FileOutputStream(dst), man);
+                       {
+                               String[] dirs = {"maps/", "tiles/"};
+                               for (String d : dirs) {
+                                       JarEntry je = new JarEntry(d);
+                                       jos.putNextEntry(je);
+                                       jos.closeEntry();
+                               }
+                       }
+
+                       TileMap map = new TileMap(tmap.getWidth(), tmap.getHeight());
+
+                       int lid = 0;
+
+                       for (Object o : tmap.getLayerOrObjectgroup()) {
+                               if (o instanceof Layer) {
+                                       Layer l = (Layer) o;
+
+                                       // FIXME: remap map?
+                                       //l.getData().getvalue();
+
+                                       // encoding blah blah
+
+                                       InputStream is = decodeArray(l.getData().getvalue());
+                                       ImageInputStream dis = new MemoryCacheImageInputStream(is);
+
+                                       dis.setByteOrder(ByteOrder.LITTLE_ENDIAN);
+
+                                       // Convert to shorts
+                                       JarEntry je = new JarEntry("maps/0-" + lid + "-" + l.getName());
+                                       jos.putNextEntry(je);
+
+                                       DataOutputStream dos = new DataOutputStream(jos);
+                                       dos.writeInt(l.getWidth());
+                                       dos.writeInt(l.getHeight());
+                                       for (int y = 0; y < l.getHeight(); y++) {
+                                               for (int x = 0; x < l.getWidth(); x++) {
+                                                       int t = dis.readInt();
+                                                       dos.writeShort(t);
+                                                       //System.out.printf("%3d\n", t);
+                                               }
+                                       }
+                                       dos.flush();
+                                       //dos.close();
+
+                                       jos.closeEntry();
+                               }
+                       }
+
+                       // Add tile script names
+                       {
+                               JarEntry je = new JarEntry("tiles/scripts");
+                               jos.putNextEntry(je);
+                               PrintStream ps = new PrintStream(jos);
+                               for (TileInfo ti : tileInfo) {
+                                       if (ti.move != null && !ti.move.equals("false")) {
+                                               ps.format("move.%d=%s\n", ti.id, ti.move);
+                                       }
+                                       if (ti.see != null && !ti.see.equals("false")) {
+                                               ps.format("see.%d=%s\n", ti.id, ti.see);
+                                       }
+                                       if (ti.action != null) {
+                                               ps.format("action.%d=%s\n", ti.id, ti.action);
+                                       }
+                               }
+                               ps.flush();
+                               jos.closeEntry();
+                       }
+
+                       // Build tileset manifest - nope in manifest
+                       if (false) {
+                               int setid = 0;
+                               JarEntry je = new JarEntry("tiles/manifest");
+                               jos.putNextEntry(je);
+                               PrintStream ps = new PrintStream(jos);
+                               for (Tileset ts : tmap.getTileset()) {
+                                       int gid0 = ts.getFirstgid();
+
+                                       if (ts.getSource() != null) {
+                                               URI uri = src.toURI().resolve(ts.getSource());
+
+                                               ts = (Tileset) u.unmarshal(new File(uri));
+                                       }
+                                       if (!ts.getTile().isEmpty()) {
+                                               Tile tt = ts.getTile().get(0);
+                                               BufferedImage image = decodeImage(tt.getImage().getData().getvalue());
+
+                                               int twidth = image.getWidth();
+                                               int theight = image.getHeight();
+
+                                               ps.format("tiles.%d.name=%s\n", setid, ts.getName());
+                                               ps.format("tiles.%s.width=%d\n", setid, twidth);
+                                               ps.format("tiles.%s.height=%d\n", setid, theight);
+                                               ps.format("tiles.%s.source=tiles-%d.png\n", setid, gid0);
+                                               ps.format("tiles.%s.firstGid=%d\n", setid, gid0);
+                                               setid++;
+                                       }
+
+                               }
+                               ps.format("tiles.count=%d\n", setid);
+                               ps.flush();
+                               jos.closeEntry();
+                       }
+
+                       for (Tileset ts : tmap.getTileset()) {
+                               int gid0 = ts.getFirstgid();
+
+                               if (ts.getSource() != null) {
+                                       URI uri = src.toURI().resolve(ts.getSource());
+
+                                       ts = (Tileset) u.unmarshal(new File(uri));
+                               }
+
+
+                               int twidth = 0, theight = 0;
+                               BufferedImage tmp = null;
+                               Graphics2D gg = null;
+
+                               System.out.println("found tileset: " + ts.getName());
+
+                               int ntiles = ts.getTile().size();
+
+                               int i = 0;
+                               for (Tile tt : ts.getTile()) {
+                                       BufferedImage image = decodeImage(tt.getImage().getData().getvalue());
+
+                                       if (tmp == null) {
+                                               twidth = image.getWidth();
+                                               theight = image.getHeight();
+                                               tmp = new BufferedImage(ntiles * twidth, theight, BufferedImage.TYPE_INT_ARGB);
+                                               gg = tmp.createGraphics();
+                                       } else if (image.getWidth() != twidth || image.getHeight() != theight) {
+                                               System.out.println("Image tiles differ in size\n");
+                                       }
+
+                                       gg.drawImage(image, (i++) * twidth, 0, null);
+                               }
+
+                               if (tmp != null) {
+                                       //ImageIO.write(tmp, "png", new File("/home/notzed/tiled-tiles-" + twidth + "x" + theight + ".png"));
+
+                                       JarEntry ze = new JarEntry("tiles/tiles_" + gid0 + ".png");
+                                       jos.putNextEntry(ze);
+                                       ImageIO.write(tmp, "png", jos);
+                                       jos.closeEntry();
+                               }
+                       }
+                       jos.close();
+
+               } catch (JAXBException ex) {
+                       Logger.getLogger(Tiled.class.getName()).log(Level.SEVERE, null, ex);
+               }
+       }
+       // test load/save itled format map
+
+       public static void main(String[] args) throws IOException {
+               testimport(new File("/home/notzed/house.tmx"),
+                               new File("/home/notzed/house.jar"));
+               //testexport();
+       }
+}
diff --git a/DuskServer/src/duskz/io/tiled/Data.java b/DuskServer/src/duskz/io/tiled/Data.java
new file mode 100644 (file)
index 0000000..f6f9b8f
--- /dev/null
@@ -0,0 +1,112 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.XmlValue;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "value"
+})
+@XmlRootElement(name = "data")
+public class Data {
+
+    @XmlAttribute(name = "encoding")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String encoding;
+    @XmlAttribute(name = "compression")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String compression;
+    @XmlValue
+    protected String value;
+
+    /**
+     * Gets the value of the encoding property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getEncoding() {
+        return encoding;
+    }
+
+    /**
+     * Sets the value of the encoding property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setEncoding(String value) {
+        this.encoding = value;
+    }
+
+    /**
+     * Gets the value of the compression property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getCompression() {
+        return compression;
+    }
+
+    /**
+     * Sets the value of the compression property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setCompression(String value) {
+        this.compression = value;
+    }
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getvalue() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setvalue(String value) {
+        this.value = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Image.java b/DuskServer/src/duskz/io/tiled/Image.java
new file mode 100644 (file)
index 0000000..709c33e
--- /dev/null
@@ -0,0 +1,162 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "data"
+})
+@XmlRootElement(name = "image")
+public class Image {
+
+    @XmlAttribute(name = "format")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String format;
+    @XmlAttribute(name = "id")
+    protected String id;
+    @XmlAttribute(name = "source")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String source;
+    @XmlAttribute(name = "trans")
+    protected String trans;
+    protected Data data;
+
+    /**
+     * Gets the value of the format property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getFormat() {
+        return format;
+    }
+
+    /**
+     * Sets the value of the format property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setFormat(String value) {
+        this.format = value;
+    }
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(String value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the source property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * Sets the value of the source property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setSource(String value) {
+        this.source = value;
+    }
+
+    /**
+     * Gets the value of the trans property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getTrans() {
+        return trans;
+    }
+
+    /**
+     * Sets the value of the trans property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTrans(String value) {
+        this.trans = value;
+    }
+
+    /**
+     * Gets the value of the data property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Data }
+     *     
+     */
+    public Data getData() {
+        return data;
+    }
+
+    /**
+     * Sets the value of the data property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Data }
+     *     
+     */
+    public void setData(Data value) {
+        this.data = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Layer.java b/DuskServer/src/duskz/io/tiled/Layer.java
new file mode 100644 (file)
index 0000000..1d52347
--- /dev/null
@@ -0,0 +1,268 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "properties",
+    "data"
+})
+@XmlRootElement(name = "layer")
+public class Layer {
+
+    @XmlAttribute(name = "name", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String name;
+    @XmlAttribute(name = "width", required = true)
+    protected int width;
+    @XmlAttribute(name = "height", required = true)
+    protected int height;
+    @XmlAttribute(name = "x")
+    protected int x;
+    @XmlAttribute(name = "y")
+    protected int y;
+    @XmlAttribute(name = "opacity")
+    protected float opacity;
+    @XmlAttribute(name = "visible")
+    protected int visible;
+    protected Properties properties;
+    @XmlElement(required = true)
+    protected Data data;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the width property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Sets the value of the width property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setWidth(int value) {
+        this.width = value;
+    }
+
+    /**
+     * Gets the value of the height property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Sets the value of the height property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setHeight(int value) {
+        this.height = value;
+    }
+
+    /**
+     * Gets the value of the x property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getX() {
+        return x;
+    }
+
+    /**
+     * Sets the value of the x property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setX(int value) {
+        this.x = value;
+    }
+
+    /**
+     * Gets the value of the y property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getY() {
+        return y;
+    }
+
+    /**
+     * Sets the value of the y property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setY(int value) {
+        this.y = value;
+    }
+
+    /**
+     * Gets the value of the opacity property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public float getOpacity() {
+        return opacity;
+    }
+
+    /**
+     * Sets the value of the opacity property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setOpacity(float value) {
+        this.opacity = value;
+    }
+
+    /**
+     * Gets the value of the visible property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getVisible() {
+        return visible;
+    }
+
+    /**
+     * Sets the value of the visible property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVisible(int value) {
+        this.visible = value;
+    }
+
+    /**
+     * Gets the value of the properties property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Properties }
+     *     
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Sets the value of the properties property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Properties }
+     *     
+     */
+    public void setProperties(Properties value) {
+        this.properties = value;
+    }
+
+    /**
+     * Gets the value of the data property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Data }
+     *     
+     */
+    public Data getData() {
+        return data;
+    }
+
+    /**
+     * Sets the value of the data property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Data }
+     *     
+     */
+    public void setData(Data value) {
+        this.data = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Map.java b/DuskServer/src/duskz/io/tiled/Map.java
new file mode 100644 (file)
index 0000000..12a6585
--- /dev/null
@@ -0,0 +1,367 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlElements;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "properties",
+    "tileset",
+    "layerOrObjectgroup"
+})
+@XmlRootElement(name = "map")
+public class Map {
+
+    @XmlAttribute(name = "xmlns")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String xmlns;
+    @XmlAttribute(name = "xmlns:xsi")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String xmlnsXsi;
+    @XmlAttribute(name = "xsi:schemaLocation")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String xsiSchemaLocation;
+    @XmlAttribute(name = "version", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String version;
+    @XmlAttribute(name = "orientation", required = true)
+    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
+    protected String orientation;
+    @XmlAttribute(name = "width", required = true)
+    protected int width;
+    @XmlAttribute(name = "height", required = true)
+    protected int height;
+    @XmlAttribute(name = "tilewidth", required = true)
+    protected int tilewidth;
+    @XmlAttribute(name = "tileheight", required = true)
+    protected int tileheight;
+    protected Properties properties;
+    protected List<Tileset> tileset;
+    @XmlElements({
+        @XmlElement(name = "layer", type = Layer.class),
+        @XmlElement(name = "objectgroup", type = Objectgroup.class)
+    })
+    protected List<java.lang.Object> layerOrObjectgroup;
+
+    /**
+     * Gets the value of the xmlns property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getXmlns() {
+        return xmlns;
+    }
+
+    /**
+     * Sets the value of the xmlns property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setXmlns(String value) {
+        this.xmlns = value;
+    }
+
+    /**
+     * Gets the value of the xmlnsXsi property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getXmlnsXsi() {
+        return xmlnsXsi;
+    }
+
+    /**
+     * Sets the value of the xmlnsXsi property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setXmlnsXsi(String value) {
+        this.xmlnsXsi = value;
+    }
+
+    /**
+     * Gets the value of the xsiSchemaLocation property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getXsiSchemaLocation() {
+        return xsiSchemaLocation;
+    }
+
+    /**
+     * Sets the value of the xsiSchemaLocation property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setXsiSchemaLocation(String value) {
+        this.xsiSchemaLocation = value;
+    }
+
+    /**
+     * Gets the value of the version property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * Sets the value of the version property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVersion(String value) {
+        this.version = value;
+    }
+
+    /**
+     * Gets the value of the orientation property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getOrientation() {
+        return orientation;
+    }
+
+    /**
+     * Sets the value of the orientation property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setOrientation(String value) {
+        this.orientation = value;
+    }
+
+    /**
+     * Gets the value of the width property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Sets the value of the width property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setWidth(int value) {
+        this.width = value;
+    }
+
+    /**
+     * Gets the value of the height property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Sets the value of the height property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setHeight(int value) {
+        this.height = value;
+    }
+
+    /**
+     * Gets the value of the tilewidth property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getTilewidth() {
+        return tilewidth;
+    }
+
+    /**
+     * Sets the value of the tilewidth property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTilewidth(int value) {
+        this.tilewidth = value;
+    }
+
+    /**
+     * Gets the value of the tileheight property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getTileheight() {
+        return tileheight;
+    }
+
+    /**
+     * Sets the value of the tileheight property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTileheight(int value) {
+        this.tileheight = value;
+    }
+
+    /**
+     * Gets the value of the properties property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Properties }
+     *     
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Sets the value of the properties property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Properties }
+     *     
+     */
+    public void setProperties(Properties value) {
+        this.properties = value;
+    }
+
+    /**
+     * Gets the value of the tileset property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the tileset property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getTileset().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Tileset }
+     * 
+     * 
+     */
+    public List<Tileset> getTileset() {
+        if (tileset == null) {
+            tileset = new ArrayList<Tileset>();
+        }
+        return this.tileset;
+    }
+
+    /**
+     * Gets the value of the layerOrObjectgroup property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the layerOrObjectgroup property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getLayerOrObjectgroup().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Layer }
+     * {@link Objectgroup }
+     * 
+     * 
+     */
+    public List<java.lang.Object> getLayerOrObjectgroup() {
+        if (layerOrObjectgroup == null) {
+            layerOrObjectgroup = new ArrayList<java.lang.Object>();
+        }
+        return this.layerOrObjectgroup;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Object.java b/DuskServer/src/duskz/io/tiled/Object.java
new file mode 100644 (file)
index 0000000..fe12a79
--- /dev/null
@@ -0,0 +1,240 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "properties",
+    "image"
+})
+@XmlRootElement(name = "object")
+public class Object {
+
+    @XmlAttribute(name = "name", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String name;
+    @XmlAttribute(name = "type", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String type;
+    @XmlAttribute(name = "x", required = true)
+    protected int x;
+    @XmlAttribute(name = "y", required = true)
+    protected int y;
+    @XmlAttribute(name = "width")
+    protected int width;
+    @XmlAttribute(name = "height")
+    protected int height;
+    protected Properties properties;
+    protected Image image;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the type property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getType() {
+        return type;
+    }
+
+    /**
+     * Sets the value of the type property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setType(String value) {
+        this.type = value;
+    }
+
+    /**
+     * Gets the value of the x property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getX() {
+        return x;
+    }
+
+    /**
+     * Sets the value of the x property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setX(int value) {
+        this.x = value;
+    }
+
+    /**
+     * Gets the value of the y property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getY() {
+        return y;
+    }
+
+    /**
+     * Sets the value of the y property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setY(int value) {
+        this.y = value;
+    }
+
+    /**
+     * Gets the value of the width property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Sets the value of the width property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setWidth(int value) {
+        this.width = value;
+    }
+
+    /**
+     * Gets the value of the height property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Sets the value of the height property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setHeight(int value) {
+        this.height = value;
+    }
+
+    /**
+     * Gets the value of the properties property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Properties }
+     *     
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Sets the value of the properties property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Properties }
+     *     
+     */
+    public void setProperties(Properties value) {
+        this.properties = value;
+    }
+
+    /**
+     * Gets the value of the image property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Image }
+     *     
+     */
+    public Image getImage() {
+        return image;
+    }
+
+    /**
+     * Sets the value of the image property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Image }
+     *     
+     */
+    public void setImage(Image value) {
+        this.image = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/ObjectFactory.java b/DuskServer/src/duskz/io/tiled/ObjectFactory.java
new file mode 100644 (file)
index 0000000..1745074
--- /dev/null
@@ -0,0 +1,119 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each 
+ * Java content interface and Java element interface 
+ * generated in the generated package. 
+ * <p>An ObjectFactory allows you to programatically 
+ * construct new instances of the Java representation 
+ * for XML content. The Java representation of XML 
+ * content can consist of schema derived interfaces 
+ * and classes representing the binding of schema 
+ * type definitions, element declarations and model 
+ * groups.  Factory methods for each of these are 
+ * provided in this class.
+ * 
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: generated
+     * 
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link Tileset }
+     * 
+     */
+    public Tileset createTileset() {
+        return new Tileset();
+    }
+
+    /**
+     * Create an instance of {@link Image }
+     * 
+     */
+    public Image createImage() {
+        return new Image();
+    }
+
+    /**
+     * Create an instance of {@link Tile }
+     * 
+     */
+    public Tile createTile() {
+        return new Tile();
+    }
+
+    /**
+     * Create an instance of {@link Properties }
+     * 
+     */
+    public Properties createProperties() {
+        return new Properties();
+    }
+
+    /**
+     * Create an instance of {@link Objectgroup }
+     * 
+     */
+    public Objectgroup createObjectgroup() {
+        return new Objectgroup();
+    }
+
+    /**
+     * Create an instance of {@link Object }
+     * 
+     */
+    public Object createObject() {
+        return new Object();
+    }
+
+    /**
+     * Create an instance of {@link Data }
+     * 
+     */
+    public Data createData() {
+        return new Data();
+    }
+
+    /**
+     * Create an instance of {@link Map }
+     * 
+     */
+    public Map createMap() {
+        return new Map();
+    }
+
+    /**
+     * Create an instance of {@link Layer }
+     * 
+     */
+    public Layer createLayer() {
+        return new Layer();
+    }
+
+    /**
+     * Create an instance of {@link Property }
+     * 
+     */
+    public Property createProperty() {
+        return new Property();
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Objectgroup.java b/DuskServer/src/duskz/io/tiled/Objectgroup.java
new file mode 100644 (file)
index 0000000..06cb7fe
--- /dev/null
@@ -0,0 +1,194 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "object"
+})
+@XmlRootElement(name = "objectgroup")
+public class Objectgroup {
+
+    @XmlAttribute(name = "name", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String name;
+    @XmlAttribute(name = "width")
+    protected int width;
+    @XmlAttribute(name = "height")
+    protected int height;
+    @XmlAttribute(name = "x")
+    protected int x;
+    @XmlAttribute(name = "y")
+    protected int y;
+    protected List<Object> object;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the width property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Sets the value of the width property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setWidth(int value) {
+        this.width = value;
+    }
+
+    /**
+     * Gets the value of the height property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Sets the value of the height property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setHeight(int value) {
+        this.height = value;
+    }
+
+    /**
+     * Gets the value of the x property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getX() {
+        return x;
+    }
+
+    /**
+     * Sets the value of the x property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setX(int value) {
+        this.x = value;
+    }
+
+    /**
+     * Gets the value of the y property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getY() {
+        return y;
+    }
+
+    /**
+     * Sets the value of the y property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setY(int value) {
+        this.y = value;
+    }
+
+    /**
+     * Gets the value of the object property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the object property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getObject().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Object }
+     * 
+     * 
+     */
+    public List<Object> getObject() {
+        if (object == null) {
+            object = new ArrayList<Object>();
+        }
+        return this.object;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Properties.java b/DuskServer/src/duskz/io/tiled/Properties.java
new file mode 100644 (file)
index 0000000..97355d8
--- /dev/null
@@ -0,0 +1,60 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "property"
+})
+@XmlRootElement(name = "properties")
+public class Properties {
+
+    protected List<Property> property;
+
+    /**
+     * Gets the value of the property property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the property property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getProperty().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Property }
+     * 
+     * 
+     */
+    public List<Property> getProperty() {
+        if (property == null) {
+            property = new ArrayList<Property>();
+        }
+        return this.property;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Property.java b/DuskServer/src/duskz/io/tiled/Property.java
new file mode 100644 (file)
index 0000000..2cd68bb
--- /dev/null
@@ -0,0 +1,83 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "")
+@XmlRootElement(name = "property")
+public class Property {
+
+    @XmlAttribute(name = "name", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String name;
+    @XmlAttribute(name = "value", required = true)
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String value;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the value property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Sets the value of the value property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Tile.java b/DuskServer/src/duskz/io/tiled/Tile.java
new file mode 100644 (file)
index 0000000..f474d71
--- /dev/null
@@ -0,0 +1,134 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "properties",
+    "image"
+})
+@XmlRootElement(name = "tile")
+public class Tile {
+
+    @XmlAttribute(name = "id")
+    protected int id;
+    @XmlAttribute(name = "gid")
+    protected String gid;
+    protected Properties properties;
+    protected Image image;
+
+    /**
+     * Gets the value of the id property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getId() {
+        return id;
+    }
+
+    /**
+     * Sets the value of the id property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setId(int value) {
+        this.id = value;
+    }
+
+    /**
+     * Gets the value of the gid property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getGid() {
+        return gid;
+    }
+
+    /**
+     * Sets the value of the gid property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setGid(String value) {
+        this.gid = value;
+    }
+
+    /**
+     * Gets the value of the properties property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Properties }
+     *     
+     */
+    public Properties getProperties() {
+        return properties;
+    }
+
+    /**
+     * Sets the value of the properties property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Properties }
+     *     
+     */
+    public void setProperties(Properties value) {
+        this.properties = value;
+    }
+
+    /**
+     * Gets the value of the image property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link Image }
+     *     
+     */
+    public Image getImage() {
+        return image;
+    }
+
+    /**
+     * Sets the value of the image property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link Image }
+     *     
+     */
+    public void setImage(Image value) {
+        this.image = value;
+    }
+
+}
diff --git a/DuskServer/src/duskz/io/tiled/Tileset.java b/DuskServer/src/duskz/io/tiled/Tileset.java
new file mode 100644 (file)
index 0000000..f6afbf6
--- /dev/null
@@ -0,0 +1,279 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4-2 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2013.02.27 at 01:07:39 PM CST 
+//
+
+
+package duskz.io.tiled;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
+import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
+
+
+/**
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "image",
+    "tile"
+})
+@XmlRootElement(name = "tileset")
+public class Tileset {
+
+    @XmlAttribute(name = "name")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String name;
+    @XmlAttribute(name = "firstgid", required = true)
+    protected int firstgid;
+    @XmlAttribute(name = "source")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String source;
+    @XmlAttribute(name = "tilewidth")
+    protected int tilewidth;
+    @XmlAttribute(name = "tileheight")
+    protected int tileheight;
+    @XmlAttribute(name = "spacing")
+    protected int spacing;
+    @XmlAttribute(name = "margin")
+    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
+    protected String margin;
+    protected List<Image> image;
+    protected List<Tile> tile;
+
+    /**
+     * Gets the value of the name property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Sets the value of the name property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setName(String value) {
+        this.name = value;
+    }
+
+    /**
+     * Gets the value of the firstgid property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getFirstgid() {
+        return firstgid;
+    }
+
+    /**
+     * Sets the value of the firstgid property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setFirstgid(int value) {
+        this.firstgid = value;
+    }
+
+    /**
+     * Gets the value of the source property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getSource() {
+        return source;
+    }
+
+    /**
+     * Sets the value of the source property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setSource(String value) {
+        this.source = value;
+    }
+
+    /**
+     * Gets the value of the tilewidth property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getTilewidth() {
+        return tilewidth;
+    }
+
+    /**
+     * Sets the value of the tilewidth property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTilewidth(int value) {
+        this.tilewidth = value;
+    }
+
+    /**
+     * Gets the value of the tileheight property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getTileheight() {
+        return tileheight;
+    }
+
+    /**
+     * Sets the value of the tileheight property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setTileheight(int value) {
+        this.tileheight = value;
+    }
+
+    /**
+     * Gets the value of the spacing property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public int getSpacing() {
+        return spacing;
+    }
+
+    /**
+     * Sets the value of the spacing property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setSpacing(int value) {
+        this.spacing = value;
+    }
+
+    /**
+     * Gets the value of the margin property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getMargin() {
+        return margin;
+    }
+
+    /**
+     * Sets the value of the margin property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setMargin(String value) {
+        this.margin = value;
+    }
+
+    /**
+     * Gets the value of the image property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the image property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getImage().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Image }
+     * 
+     * 
+     */
+    public List<Image> getImage() {
+        if (image == null) {
+            image = new ArrayList<Image>();
+        }
+        return this.image;
+    }
+
+    /**
+     * Gets the value of the tile property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the tile property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getTile().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link Tile }
+     * 
+     * 
+     */
+    public List<Tile> getTile() {
+        if (tile == null) {
+            tile = new ArrayList<Tile>();
+        }
+        return this.tile;
+    }
+
+}
diff --git a/DuskServer/src/duskz/proto/Junk.java b/DuskServer/src/duskz/proto/Junk.java
new file mode 100644 (file)
index 0000000..55a337e
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Jus test code, public domain
+ */
+package duskz.proto;
+
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import javax.script.SimpleScriptContext;
+
+/**
+ * This is just a place holder to test stuff in the ide
+ *
+ *
+ * for security test: java -Djava.security.manager -Djava.security.policy=dusk.policy -classpath dist/DuskCommon.jar au.dusk.Junk
+ *
+ * @author notzed
+ */
+public class Junk {
+
+       int MapColumns = 64;
+       int MapRows = 64;
+       int viewrange = 7;
+       int mapsize = 1 + (2 * viewrange);
+
+       public void chatMessage(String inMessage, int intLocX, int intLocY, String strFrom) {
+
+               System.out.printf("look at %d,%d\n", intLocX, intLocY);
+
+
+               int mx, y0, my;
+               mx = 0;
+               if (intLocX - viewrange < 0) {
+                       mx = -1 * (intLocX - viewrange);
+               }
+               y0 = 0;
+               if (intLocY - viewrange < 0) {
+                       y0 = -1 * (intLocY - viewrange);
+               }
+               for (; mx < mapsize; mx++) {
+                       if (intLocX + mx - viewrange < MapColumns) {
+                               for (my = y0; my < mapsize; my++) {
+                                       if (intLocY + my - viewrange < MapRows) {
+                                               int x = intLocX + mx - viewrange;
+                                               int y = intLocY + my - viewrange;
+
+                                               System.out.printf("visit %d,%d\n", x, y);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public static class Thing {
+
+               FileOutputStream fos;
+
+               public Thing() {
+                       try {
+                               fos = new FileOutputStream("foo.txt");
+                       } catch (FileNotFoundException ex) {
+                               Logger.getLogger(Junk.class.getName()).log(Level.SEVERE, null, ex);
+                       }
+               }
+
+               public boolean isPet() {
+                       return false;
+               }
+
+               public boolean hasCondition(String name) {
+                       System.out.println("has trigger " + name);
+                       return true;
+               }
+
+               public void removeCondition(String name) {
+                       System.out.println("remove trigger " + name);
+               }
+
+               public void moveTo(int x, int y) {
+                       System.out.println("move to " + x + "," + y);
+               }
+
+               public void chat(String what) {
+                       try {
+                               //fos = new FileOutputStream("foo.txt");
+                               fos.write(what.getBytes());
+                               //fos.close();
+                       } catch (IOException ex) {
+                               Logger.getLogger(Junk.class.getName()).log(Level.SEVERE, null, ex);
+                       }
+               }
+       }
+       static ScriptEngine engine;
+
+       public static void main(String[] args) throws ScriptException, InterruptedException {
+               //new Junk().chatMessage(null, 16, 16, null);
+               //new Junk().chatMessage(null, 2, 2, null);
+               // create a script engine manager
+               // evaluate JavaScript code from given file - specified by first argument
+
+
+               try (FileOutputStream fos = new FileOutputStream("not-hack-a")) {
+                       fos.write(1);
+                       System.out.println("wrote not-hack-a");
+               } catch (IOException x) {
+                       x.printStackTrace();
+               } catch (AccessControlException x) {
+                       x.printStackTrace();
+               }
+
+
+               /*
+                SecurityManager sm = new SecurityManager() {
+                @Override
+                public void checkPermission(Permission perm, Object context) {
+                System.out.println("check perm ctx " + perm);
+                super.checkPermission(perm, context);
+
+                }
+
+                @Override
+                public void checkPermission(Permission perm) {
+                System.out.println("check perm " + perm);
+                super.checkPermission(perm);
+                }
+                };*/
+               //System.setSecurityManager(sm);
+
+
+               //System.setSecurityManager(new SecurityManager());
+
+               final Thing thing = new Thing();
+
+
+               Permissions perms = new Permissions();
+               //perms.add(new AllPermission());
+               //perms.add(new FilePermission("hack.txt", "read,write"));
+               //      perms.add(new NetPermission("*"));
+               //perms.add(new RuntimePermission("accessDeclaredMembers"));
+               // Cast to Certificate[] required because of ambiguity:
+               ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
+               AccessControlContext ac = new AccessControlContext(
+                               new ProtectionDomain[]{domain});
+
+               // This doesn't work: security permissions are lost in the next thing.
+               // bloody odd if you ask me
+               AccessController.doPrivileged(new PrivilegedAction<ScriptEngine>() {
+                       @Override
+                       public ScriptEngine run() {
+                               ScriptEngineManager factory = new ScriptEngineManager();
+                               engine = factory.getEngineByName("JavaScript");
+                               return null;
+                       }
+               });
+
+
+               AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                       @Override
+                       public Object run() {
+                               ScriptEngineManager factory = new ScriptEngineManager();
+                               engine = factory.getEngineByName("JavaScript");
+
+                               ScriptContext ctx = new SimpleScriptContext();
+                               ctx.getBindings(ScriptContext.ENGINE_SCOPE);
+
+                               System.out.println("threaded = " + engine.getFactory().getParameter("THREADING"));
+
+                               engine.put("trigger", thing);
+
+                               Runnable r = new Runnable() {
+                                       @Override
+                                       public void run() {
+                                               try {
+                                                       String s = "var out = new java.io.FileOutputStream('hack-thread.txt');"
+                                                                       + " out.write(65);"
+                                                                       + "out.close();"
+                                                                       + " println('write hack.txt');";
+                                                       engine.eval(s);
+                                               } catch (ScriptException ex) {
+                                                       ex.printStackTrace(System.out);
+                                               } catch (AccessControlException x) {
+                                                       x.printStackTrace(System.out);
+                                               }
+                                       }
+                               };
+                               Thread t = new Thread(r);
+                               t.start();
+                               
+                               try {
+                                       engine.eval("println(\"hello world\");");
+                                       engine.eval("trigger.chat('this is a chat message from sandbox?');");
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+                               try {
+                                       String s = "if (!trigger.isPet() &&"
+                                                       + "trigger.hasCondition(\"walk\")) {"
+                                                       + " trigger.removeCondition(\"walk\");"
+                                                       + "trigger.moveTo(177,195);"
+                                                       + "}";
+
+                                       engine.eval(s);
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+                               try {
+                                       String s = "var out = java.lang.System.out;"
+                                                       + " out.println('system out');";
+                                       engine.eval(s);
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+                               try {
+                                       String s = "var out = new java.io.FileOutputStream('hack.txt');"
+                                                       + " out.write(65);"
+                                                       + "out.close();"
+                                                       + " println('write hack.txt');";
+                                       engine.eval(s);
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+
+                               try {
+                                       String s = "var out = new java.net.Socket('localhost', 7475);;"
+                                                       + " println(out);";
+                                       engine.eval(s);
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+                               try {
+                                       String s = "var out = new java.lang.Thread();"
+                                                       + " println(out);";
+                                       engine.eval(s);
+                               } catch (ScriptException ex) {
+                                       ex.printStackTrace(System.out);
+                               } catch (AccessControlException x) {
+                                       x.printStackTrace(System.out);
+                               }
+                               return null;
+                       }
+               }, ac);
+
+               try (FileOutputStream fos = new FileOutputStream("not-hack-b")) {
+                       fos.write(1);
+                       System.out.println("wrote not-hack-b");
+               } catch (IOException x) {
+                       x.printStackTrace();
+               } catch (AccessControlException x) {
+                       x.printStackTrace(System.out);
+               }
+
+       }
+}
diff --git a/DuskServer/src/duskz/server/Battle.java b/DuskServer/src/duskz/server/Battle.java
new file mode 100644 (file)
index 0000000..87418ed
--- /dev/null
@@ -0,0 +1,723 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - Pretty major cleanup and parameterisation of code.
+ */
+package duskz.server;
+
+import duskz.protocol.MessageType;
+import duskz.server.entity.Mob;
+import duskz.server.entity.LivingThing;
+import duskz.server.entity.Item;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ * Battle represents a fight between two sides comprised of LivingThings.
+ *
+ * TODO: Remove the general chat stuff and use specific message types where appropriate
+ *
+ * @author Tom Weingarten
+ */
+public class Battle {
+
+       private ArrayList<LivingThing> vctSide1 = new ArrayList<>(),
+                       vctSide2 = new ArrayList<>();
+       DuskEngine engGame;
+       boolean blnRunning = true,
+                       blnPlayerSide1 = false,
+                       blnPlayerSide2 = false;
+       private HashMap<Long, LinkedList<String>> commands = new HashMap<>();
+
+       Battle(LivingThing inpla1, LivingThing inpla2, DuskEngine inengGame) {
+               LivingThing thnFront1,
+                               thnFront2;
+               try {
+                       engGame = inengGame;
+                       thnFront2 = inpla2;
+                       while (thnFront2 != null) {
+                               blnPlayerSide2 = addToBattle(2, vctSide2, vctSide1, thnFront2, blnPlayerSide2, blnPlayerSide1);
+                               //addToBattle(thnFront2, 2);
+                               thnFront2 = thnFront2.getFollowing();
+                       }
+                       thnFront2 = inpla2.getMaster();
+                       while (thnFront2 != null) {
+                               blnPlayerSide2 = addToBattle(2, vctSide2, vctSide1, thnFront2, blnPlayerSide2, blnPlayerSide1);
+                               //addToBattle(thnFront2, 2);
+                               thnFront2 = thnFront2.getMaster();
+                       }
+                       thnFront2 = inpla2;
+                       thnFront1 = inpla1;
+                       while (thnFront1 != null) {
+                               //addToBattle(thnFront1, 1);
+                               blnPlayerSide1 = addToBattle(1, vctSide1, vctSide2, thnFront1, blnPlayerSide1, blnPlayerSide2);
+                               thnFront1 = thnFront1.getFollowing();
+                       }
+                       thnFront1 = inpla1.getMaster();
+                       while (thnFront1 != null) {
+                               blnPlayerSide1 = addToBattle(1, vctSide1, vctSide2, thnFront1, blnPlayerSide1, blnPlayerSide2);
+                               //addToBattle(thnFront1, 1);
+                               thnFront1 = thnFront1.getMaster();
+                       }
+                       thnFront1 = inpla1;
+                       engGame.chatMessage("-" + inpla1.name + " has attacked " + inpla2.name, inpla1.x, inpla1.y, "default");
+                       if (inpla1.popup) {
+                               inpla1.send(MessageType.StartBattle, inpla2.name + "\n");
+                       }
+                       if (inpla2.popup) {
+                               inpla2.send(MessageType.StartBattle, inpla1.name + "\n");
+                       }
+               } catch (Exception e) {
+                       blnRunning = false;
+                       engGame.log.printError("Battle()", e);
+               }
+       }
+
+       public static LivingThing getEnemy(LivingThing lt) {
+               if (lt.battleSide == 1) {
+                       return (LivingThing) lt.battle.vctSide2.get(0);
+               } else if (lt.battleSide == 2) {
+                       return (LivingThing) lt.battle.vctSide1.get(0);
+               } else {
+                       return null;
+               }
+       }
+
+       public void addToBattle(LivingThing lt, int side) {
+               if (side == 1) {
+                       blnPlayerSide1 = addToBattle(1, vctSide1, vctSide2, lt, blnPlayerSide1, blnPlayerSide2);
+               } else {
+                       blnPlayerSide2 = addToBattle(2, vctSide2, vctSide1, lt, blnPlayerSide2, blnPlayerSide1);
+               }
+       }
+
+       boolean addToBattle(int sideid, ArrayList<LivingThing> side, ArrayList<LivingThing> opponents, LivingThing thnAdded, boolean playerSide, boolean playerOpponent) {
+               if (thnAdded.isPlayer()) {
+                       if (playerOpponent) {
+                               if (thnAdded.clan.equals("none")) {
+                                       thnAdded.chatMessage("Players who are not in clans cannot fight other players.");
+                                       thnAdded.removeFromGroup();
+                                       return playerSide;
+                               }
+                               LivingThing thnStore = side.get(0);
+                               if (thnStore.clan.equals("none")) {
+                                       thnAdded.chatMessage("Players who are not in clans cannot fight other players.");
+                                       thnAdded.removeFromGroup();
+                                       return playerSide;
+                               }
+                       }
+                       playerSide = true;
+                       if (engGame.blnMusic) {
+                               thnAdded.playMusic(1);
+                       }
+               }
+               chatMessage("\t" + thnAdded.name + " has joined the battle.");
+               side.add(thnAdded);
+               thnAdded.enterBattle(this, sideid);
+
+               for (LivingThing lt : side) {
+                       if (lt.highlight) {
+                               lt.updateFlag(thnAdded.ID, 1);
+                       }
+                       if (thnAdded.highlight) {
+                               thnAdded.updateFlag(lt.ID, 1);
+                       }
+               }
+               for (LivingThing lt : opponents) {
+                       if (lt.highlight) {
+                               lt.updateFlag(thnAdded.ID, 2);
+                       }
+                       if (thnAdded.highlight) {
+                               thnAdded.updateFlag(lt.ID, 2);
+                       }
+               }
+               return playerSide;
+       }
+
+       String attack(LivingThing attackor, LivingThing attackee, int range, String s) {
+               // The farther away the target, the harder they are to hit.
+               // The more skilled the attecker is in ranged combat, the less range affects ability to hit.
+               // The farther away the target, the easier it is for them to dodge.
+               // The more skilled the attecker is in ranged combat, the harder it is for the target to dodge.
+               int r2 = 0;
+               if (range > 1) {
+//                     r2= thnAttacking.getSkill("ranged combat") - (int)((range * range - 1) * (double)(100/engGame.viewrange));
+                       r2 = attackor.getSkill("ranged combat");
+               } else {
+                       r2 = attackor.getSkill("close combat");
+               }
+               if (r2 < 0) {
+                       s += attackor.name + " missed.";
+                       hitMessage(attackee.getID(), 0, attackee.hp, attackee.maxhp, attackor.getID(), "Missed!");
+               } else if (dodge(attackor, attackee, r2)) {
+                       s += attackee.name + " dodged " + attackor.name + "'s attack";
+                       hitMessage(attackee.getID(), 0, attackee.hp, attackee.maxhp, attackor.getID(), "Dodged!");
+               } else {
+                       if (engGame.battlesound != -1) {
+                               engGame.playSound(engGame.battlesound, attackee.x, attackee.y);
+                       }
+                       int i = damRoll(attackor, attackee, range);
+                       if (i < 0) {
+                               i = 0;
+                       }
+                       s += attackor.name + " did " + i + " to " + attackee.name;
+                       attackee.hp -= i;
+                       attackor.damageDone += i;
+                       attackor.weaponDam(i);
+                       attackee.armorDam(i);
+
+                       hitMessage(attackee.getID(), i, attackee.hp, attackee.maxhp, attackor.getID(), "Hit!");
+               }
+               return s;
+       }
+
+       /**
+        * Attack everything in side1 against side2
+        *
+        * @param list1
+        * @param list2
+        * @return true if the battle continues
+        */
+       boolean attackSide(ArrayList<LivingThing> list1, ArrayList<LivingThing> list2) {
+               int range;
+               LivingThing target;
+               String msg;
+
+               checkCommands(list1, list2);
+               if (list1.isEmpty()) {
+                       endBattle();
+                       return false;
+               }
+
+               for (LivingThing attackor : list1) {
+                       msg = "";
+                       if (attackor.isMob()) {
+                               Mob mobStore = (Mob) attackor;
+                               mobStore.onBattle(engGame);
+                       }
+
+                       range = Integer.MAX_VALUE;
+                       target = null;
+                       attackor.isMoveable = true;
+                       for (LivingThing t : list2) {
+                               int distance = attackor.distance(t);
+                               if (distance < range) {
+                                       range = distance;
+                                       target = t;
+                               }
+                               /*
+                                They are allowed to move until they are at a range of 1 or less with any target
+                                */
+                               t.isMoveable = true;
+                               if (attackor.adjacent(t)) {
+                                       attackor.isMoveable = false;
+                                       t.isMoveable = false;
+                               }
+                       }
+
+                       /*
+                        End the battle if the closest target is off of the screen.
+                        */
+                       if (range > engGame.viewrange) {
+                               endBattle();
+                               return false;
+                       }
+                       if (range > attackor.getRangeWithBonus()) {
+                               msg = attackor.name + " is out of range.\n";
+                               if (attackor.isMob() && !attackor.hasPendingMoves()) // if mob, try to go to the enemy to fight them
+                               {
+                                       attackor.goTo(target.x, target.y, false);
+                               }
+                       } else {
+                               if (attackor.isMob())
+                                       attackor.clearMoveQueue();
+                               msg = attack(attackor, target, range, msg);
+                               if (((Math.random() * 100) + 1) < attackor.getSkill("double attack")) {
+                                       msg += ",";
+                                       msg = attack(attackor, target, range, msg);
+                               }
+                               if (((Math.random() * 100) + 1) < attackor.getSkill("triple attack")) {
+                                       msg += ",";
+                                       msg = attack(attackor, target, range, msg);
+                               }
+                               if (((Math.random() * 100) + 1) < attackor.getSkill("quadruple attack")) {
+                                       msg += ",";
+                                       msg = attack(attackor, target, range, msg);
+                               }
+                               msg += ".";
+                       }
+                       chatMessage("\t" + msg);
+               }
+               return true;
+       }
+
+       int damRoll(LivingThing attacker, LivingThing thnAttacked, int range) {
+               int attackerTotal = attacker.stre + attacker.strebon;
+               return (int) (((double) (attackerTotal) / 2) * (Math.random() + 0.5) * (attacker.getDamModWithBonus() / 100) - (thnAttacked.getArmorModWithBonus()));
+       }
+
+       boolean dodge(LivingThing attacker, LivingThing thnAttacked, int attackModifier) {
+               int attackedTotal = thnAttacked.dext + thnAttacked.dextbon;
+               if (attackedTotal > 100) {
+                       attackedTotal = 100;
+               }
+               int attackerTotal = attacker.dext + attacker.dextbon + attackModifier;
+               if (attackerTotal > 100) {
+                       attackerTotal = 100 + attackModifier;
+               }
+               return ((Math.random() * 100) < ((thnAttacked.getSkill("Dodge") * .75) + (.25 * (attackedTotal - attackerTotal))));
+       }
+
+       void endBattle(ArrayList<LivingThing> list) {
+               for (LivingThing lt : list) {
+                       lt.clearFlags();
+                       lt.battle = null;
+                       lt.battleSide = 0;
+                       lt.isMoveable = true;
+                       lt.updateInfo();
+                       lt.updateStats();
+                       lt.updateActions();
+                       lt.playMusic(0);
+               }
+       }
+
+       void endBattle() {
+               blnRunning = false;
+               chatMessage("\tYou have won the battle.");
+               endBattle(vctSide1);
+               endBattle(vctSide2);
+       }
+
+       void flee(LivingThing thnStore, ArrayList<LivingThing> list, ArrayList<LivingThing> opponents) {
+               thnStore.clearFlags();
+
+               updateFlagsSelf(vctSide1, 0);
+               updateFlagsSelf(vctSide2, 0);
+
+               if (thnStore.getFollowing() != null && thnStore.getFollowing().isPet()) {
+                       if (thnStore.getMaster() != null) {
+                               thnStore.getMaster().setFollowing(thnStore.getFollowing().getFollowing());
+                       }
+                       if (thnStore.getFollowing().getFollowing() != null) {
+                               thnStore.getFollowing().getFollowing().setMaster(thnStore.getMaster());
+                       }
+               } else {
+                       if (thnStore.getMaster() != null) {
+                               thnStore.getMaster().setFollowing(thnStore.getFollowing());
+                       }
+                       if (thnStore.getFollowing() != null) {
+                               thnStore.getFollowing().setMaster(thnStore.getMaster());
+                       }
+               }
+               list.remove(thnStore);
+               if (thnStore.popup) {
+                       thnStore.send("" + (char) 33 + "You have fled from battle\n");
+               } else {
+                       thnStore.chatMessage("You have fled from battle");
+               }
+               splitMoney(thnStore, (int) (thnStore.cash * engGame.gpfleemod), opponents);
+               splitExp(thnStore, (int) (thnStore.exp * engGame.expfleemod), opponents);
+               thnStore.leaveBattle();
+               thnStore.updateInfo();
+               thnStore.updateStats();
+               thnStore.updateActions();
+               thnStore.playMusic(0);
+               if (thnStore.getFollowing() != null && thnStore.getFollowing().isPet()) {
+                       list.remove(thnStore.getFollowing());
+                       updateFlags(vctSide1, thnStore.getFollowing().ID, 0);
+                       updateFlags(vctSide2, thnStore.getFollowing().ID, 0);
+                       thnStore.getFollowing().leaveBattle();
+               }
+               if (vctSide2.size() == 0 || vctSide1.size() == 0) {
+                       endBattle();
+                       return;
+               }
+       }
+
+       void splitMoney(LivingThing thnStore, int money, ArrayList<LivingThing> opponents) {
+               if (money == 0) {
+                       return;
+               }
+               if (thnStore.popup) {
+                       thnStore.send("" + (char) 33 + "You have lost " + money + " gp.\n");
+               } else {
+                       thnStore.chatMessage("You have lost " + money + " gp.");
+               }
+               thnStore.cash -= money;
+               int i,
+                               i2 = 0;
+               LivingThing thnStore2;
+               try {
+                       /*
+                        for (i=0;i<vctStore.size();i++)
+                        {
+                        thnStore2 = (LivingThing)vctStore.elementAt(i);
+                        // added  "|| thnStore2.isPet()"
+                        if (thnStore2.isPlayer() || thnStore2.isPet())
+                        {
+                        i2++;
+                        }
+                        }
+                        i2 = money/i2;
+                        */
+                       i2 = money / opponents.size();
+                       for (i = 0; i < opponents.size(); i++) {
+                               thnStore2 = (LivingThing) opponents.get(i);
+                               thnStore2.cash += i2;
+                               if (thnStore2.isPlayer() && i2 != 0) {
+                                       thnStore2.chatMessage("\tYou get " + i2 + " gp.");
+                               }
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("splitMoney()", e);
+               }
+       }
+
+       void splitExp(LivingThing thnFront, int exp, ArrayList<LivingThing> opponents) {
+               if (thnFront.popup) {
+                       thnFront.send("" + (char) 33 + "You have lost " + exp + " exp.\n");
+               } else {
+                       thnFront.chatMessage("You have lost " + exp + " exp.");
+               }
+               thnFront.exp -= exp;
+               double tp,
+                               sidepoints = 0;
+               //LivingThing thnFront;
+               //if (thnFront.bytSide == 1) {
+               //      thnFront = vctSide1.get(0);
+               //} else {
+               //      thnFront = vctSide2.get(0);
+               //}
+               int i,
+                               i2 = 0;
+               LivingThing thnStore2;
+
+               tp = thnFront.getTotalPoints();
+               thnFront.damageDone = 0;
+               for (i = 0; i < opponents.size(); i++) {
+                       thnStore2 = (LivingThing) opponents.get(i);
+// added  "|| thnStore2.isPet()"
+// and changed "thnStore.getTotalPoints()" to "thnStore2.getTotalPoints()"
+//                     if (thnStore2.isPlayer() || thnStore2.isPet())
+//                     {
+                       sidepoints += thnStore2.getTotalPoints();
+//                     }
+               }
+               try {
+                       for (i = 0; i < opponents.size(); i++) {
+                               i2 = 0;
+                               thnStore2 = (LivingThing) opponents.get(i);
+                               if (!thnStore2.isMob()) {
+                                       if (thnStore2.damageDone > thnFront.maxhp) {
+                                               thnStore2.damageDone = thnFront.maxhp;
+                                       }
+                                       i2 = (int) (engGame.expgainmod
+                                                       * (((tp / sidepoints)
+                                                       + (2 * (thnStore2.damageDone / (double) thnFront.maxhp) * (tp / (double) thnStore2.getTotalPoints()))) / 3));
+                                       thnStore2.chatMessage("You get " + i2 + " exp.");
+                                       thnStore2.exp += i2;
+                               }
+                               thnStore2.damageDone = 0;
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("splitExp()", e);
+               }
+       }
+
+       void chatMessage(ArrayList<LivingThing> side1, ArrayList<LivingThing> side2, String strStore) {
+               LivingThing thnStore = null;
+               String strStore2 = null;
+               if (!side2.isEmpty()) {
+                       thnStore = (LivingThing) side2.get(0);
+                       strStore2 = thnStore.name + " has " + thnStore.getCharacterPoints() + "cp and " + thnStore.hp + "/" + thnStore.maxhp + "hp.";
+               }
+               for (int i = 0; i < side1.size(); i++) {
+                       thnStore = (LivingThing) side1.get(i);
+                       if (thnStore.isPlayer()) {
+                               if (thnStore.popup) {
+                                       if (strStore2 != null) {
+                                               thnStore.send(MessageType.UpdateBattle, strStore2 + "\n");
+                                               thnStore.send(MessageType.LogBattle, strStore + "\n");
+                                       }
+                               } else {
+                                       thnStore.chatMessage(strStore);
+                               }
+                       } else if (thnStore.isPet()) {
+                               if (thnStore.getMaster().battle != thnStore.battle) {
+                                       if (thnStore.getMaster().popup) {
+                                               if (strStore2 != null) {
+                                                       thnStore.getMaster().send(MessageType.UpdateBattle, "From " + thnStore.name + ": " + strStore2 + "\n");
+                                                       thnStore.getMaster().send(MessageType.LogBattle, "From " + thnStore.name + ": " + strStore + "\n");
+                                               }
+                                       } else {
+                                               thnStore.chatMessage(strStore);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       void chatMessage(String strStore) {
+               chatMessage(vctSide1, vctSide2, strStore);
+               chatMessage(vctSide2, vctSide1, strStore);
+       }
+
+       void battleMessage(ArrayList<LivingThing> side1, MessageType type, String msg) {
+               for (LivingThing thnStore : side1) {
+                       if (thnStore.isPlayer()) {
+                               thnStore.send(type, msg);
+                       } else if (thnStore.isPet()) {
+                               if (thnStore.getMaster().battle != thnStore.battle) {
+                                       thnStore.send(type, msg);
+                               }
+                       }
+               }
+       }
+
+       /**
+        * New battle interface with more detailed messages
+        *
+        * @param type
+        * @param msg
+        */
+       void battleMessage(MessageType type, String msg) {
+               battleMessage(vctSide1, type, msg);
+               battleMessage(vctSide2, type, msg);
+       }
+
+       void hitMessage(long targetid, int delta, int targethp, int targettotalhp, long fromid, String what) {
+               battleMessage(MessageType.HitEntity,
+                               String.format("%d\n%d\n%d\n%d\n%d\n%s\n.\n", targetid, delta, targethp, targettotalhp, fromid, what));
+       }
+
+       /**
+        * Add a command to a current battle
+        *
+        * @param lt
+        * @param cmd
+        */
+       public void addCommand(LivingThing lt, String cmd) {
+               synchronized (commands) {
+                       LinkedList<String> clist = commands.get(lt.ID);
+                       if (clist == null) {
+                               clist = new LinkedList<>();
+                               commands.put(lt.ID, clist);
+                       }
+                       clist.add(cmd);
+               }
+       }
+
+       /**
+        * Add an expidited command to the current battle. i.e. flee
+        *
+        * @param lt
+        * @param cmd
+        */
+       public void addFirstCommand(LivingThing lt, String cmd) {
+               synchronized (commands) {
+                       LinkedList<String> clist = commands.get(lt.ID);
+                       if (clist == null) {
+                               clist = new LinkedList<>();
+                               commands.put(lt.ID, clist);
+                       }
+                       clist.addFirst(cmd);
+               }
+       }
+
+       void checkCommands(ArrayList<LivingThing> list, ArrayList<LivingThing> opponents) {
+               for (LivingThing lt : list) {
+                       String cmd = null;
+                       synchronized (commands) {
+                               LinkedList<String> clist = commands.get(lt.ID);
+                               if (clist != null) {
+                                       cmd = clist.removeFirst();
+                               }
+                       }
+                       if (cmd != null) {
+                               if (cmd.equalsIgnoreCase("flee")) {
+                                       flee(lt, list, opponents);
+                               } else if (cmd.startsWith("cast ")) {
+                                       cmd = cmd.substring(5, cmd.length());
+                                       lt.castSpell(cmd);
+                               } else if (cmd.startsWith("use ")) {
+                                       cmd = cmd.substring(4, cmd.length());
+                                       lt.useItem(cmd, -1);
+                               } else if (cmd.startsWith("eat ")) {
+                                       cmd = cmd.substring(4, cmd.length());
+                                       lt.useItem(cmd, Item.FOOD);
+                               } else if (cmd.startsWith("drink ")) {
+                                       cmd = cmd.substring(6, cmd.length());
+                                       lt.useItem(cmd, Item.DRINK);
+                               }
+                       }
+               }
+       }
+
+       void update(ArrayList<LivingThing> list) {
+               for (LivingThing lt : list) {
+                       if (lt.isPlayer()) {
+                               lt.updateInfo();
+                               lt.updateStats();
+                       }
+               }
+       }
+
+       void update() {
+               update(vctSide1);
+               update(vctSide2);
+       }
+
+       void updateFlags(ArrayList<LivingThing> list, long ID, int flag) {
+               for (LivingThing lt : list) {
+                       lt.updateFlag(ID, flag);
+               }
+       }
+
+       void updateFlagsSelf(ArrayList<LivingThing> list, int flag) {
+               for (LivingThing lt : list) {
+                       lt.updateFlag(lt.ID, flag);
+               }
+       }
+
+       void checkDeath(ArrayList<LivingThing> vctSide1, ArrayList<LivingThing> vctSide2) {
+               // FIXME: verify this works.  this protects the second call 
+               if (vctSide1.isEmpty() || vctSide2.isEmpty())
+                       return;
+
+               LivingThing thnFront1 = vctSide1.get(0);
+               LivingThing thnFront2 = vctSide2.get(0);
+
+               if (thnFront2.hp < 1 || !thnFront2.isWorking) {
+                       vctSide2.remove(0);
+
+                       System.out.println(thnFront2 + " died\nRemaining in fight:");
+                       for (LivingThing lt : vctSide2) {
+                               System.out.println(" " + lt);
+                       }
+
+                       thnFront2.clearFlags();
+                       updateFlags(vctSide1, thnFront2.ID, 0);
+                       updateFlags(vctSide2, thnFront2.ID, 0);
+                       if (thnFront2.isPlayer()) {
+                               thnFront2.removeFromGroup();
+                               chatMessage("\t" + thnFront2.name + " is killed.");
+                               if (thnFront2.popup) {
+                                       thnFront2.send("" + (char) 33 + "\tYou have died.\n");
+                               } else {
+                                       thnFront2.chatMessage("\tYou have died.");
+                               }
+                               splitMoney(thnFront2, (int) (thnFront2.cash * engGame.gplosemod), vctSide1);
+                               splitExp(thnFront2, (int) (thnFront2.exp * engGame.explosemod), vctSide1);
+                               thnFront2.leaveBattle();
+                               thnFront2.updateInfo();
+                               thnFront2.updateStats();
+                               thnFront2.updateActions();
+                               thnFront2.playMusic(0);
+                               engGame.chatMessage(thnFront2.name + " has been killed by " + thnFront1.name, "default");
+                               if (engGame.scrOnDeath != null && thnFront2.isWorking) {
+                                       engGame.scrOnDeath.varVariables.clearVariables();
+                                       engGame.scrOnDeath.varVariables.addVariable("trigger", thnFront2);
+                                       engGame.scrOnDeath.varVariables.addVariable("killer", thnFront1);
+                                       engGame.scrOnDeath.runScript();
+                               }
+                               if (thnFront2.getFollowing() != null && thnFront2.getFollowing().isPet()) {
+                                       vctSide2.remove(thnFront2.getFollowing());
+                                       updateFlags(vctSide1, thnFront2.getFollowing().ID, 0);
+                                       updateFlags(vctSide2, thnFront2.getFollowing().ID, 0);
+                                       thnFront2.getFollowing().leaveBattle();
+                                       thnFront2.getFollowing().damageDone = 0;
+                                       thnFront2.getFollowing().changeLocBypass(thnFront2.x, thnFront2.y);
+                               }
+                       } else if (thnFront2.isMob()) {
+                               Mob mob = (Mob) thnFront2;
+                               chatMessage("\t" + thnFront2.name + " is killed.");
+                               splitMoney(thnFront2, (int) (thnFront2.cash), vctSide1);
+                               splitExp(thnFront2, 0, vctSide1);
+                               /**
+                                * FIXME: Mobs are not fully removed from the game when they die.
+                                * This seems very questionable, shouldn't they just be changed
+                                * to "dead"?
+                                */
+                               mob.leaveBattle();
+                               //              if (mob.blnOneUse) {
+                               //                      engGame.removeDuskObject(mob);
+                               //              } else {
+                               //                      //engGame.removeDuskObject(mob);
+                               //                      // Marks mob as "dead"
+                               //                      mob.leaveBattle();
+                               //              }
+                               for (LivingThing lt : vctSide1) {
+                                       if (!lt.isPet()) {
+                                               try {
+                                                       mob.fctFaction.killedBy(mob, lt);
+                                               } catch (Exception e) {
+                                                       engGame.log.printError("Battle.run():While updating faction for mob " + mob.name, e);
+                                               }
+                                       }
+                               }
+                               if (thnFront1.isPlayer()) {
+                                       Item itmStore;
+                                       for (GiveItem gitStore : mob.vctGiveItems) {
+                                               if (Math.random() < gitStore.dblProbability) {
+                                                       itmStore = engGame.getItem(gitStore.strItemName);
+                                                       if (itmStore != null) {
+                                                               // FIXME: giveItem() on livingthing?
+                                                               thnFront1.chatMessage("You got a " + gitStore.strItemName + ".");
+                                                               thnFront1.itemList.addElement(itmStore);
+                                                               itmStore.onGetItem(engGame, thnFront1);
+                                                               thnFront1.updateItems();
+                                                       }
+                                               }
+                                       }
+                               }
+                       } else if (thnFront2.isPet()) {
+                               chatMessage("\t" + thnFront2.name + " is wounded.");
+                               thnFront2.chatMessage("\tYou have been wounded.");
+                               splitMoney(thnFront2, (int) (thnFront2.cash * engGame.gplosemod), vctSide1);
+                               splitExp(thnFront2, (int) (thnFront2.exp * engGame.explosemod), vctSide1);
+                               thnFront2.leaveBattle();
+                       }
+                       //if (!vctSide2.isEmpty()) {
+                       //      thnFront2 = vctSide2.get(0);
+                       //}
+               }
+       }
+
+       public void run() {
+               if (!attackSide(vctSide1, vctSide2)) {
+                       return;
+               }
+               if (!attackSide(vctSide2, vctSide1)) {
+                       return;
+               }
+
+               checkDeath(vctSide1, vctSide2);
+               checkDeath(vctSide2, vctSide1);
+
+               if (vctSide2.isEmpty() || vctSide1.isEmpty()) {
+                       endBattle();
+                       return;
+               }
+               update();
+       }
+}
diff --git a/DuskServer/src/duskz/server/Commands.java b/DuskServer/src/duskz/server/Commands.java
new file mode 100644 (file)
index 0000000..01a790c
--- /dev/null
@@ -0,0 +1,2581 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java
+ */
+package duskz.server;
+
+import duskz.server.entity.Mob;
+import duskz.server.entity.Merchant;
+import duskz.server.entity.Sign;
+import duskz.server.entity.Item;
+import duskz.server.entity.Prop;
+import duskz.server.entity.DuskObject;
+import duskz.server.entity.Equipment;
+import duskz.server.entity.PlayerMerchant;
+import duskz.server.entity.LivingThing;
+import java.io.*;
+import java.util.LinkedList;
+import java.util.StringTokenizer;
+
+public class Commands {
+
+       public static String parseCommand(LivingThing lt, DuskEngine game, String cmdline) throws Exception {
+               if (cmdline == null) {
+                       return null;
+               }
+               if (lt == null) {
+                       return null;
+               }
+               if (game == null) {
+                       return null;
+               }
+
+               String cmd = null;
+               String args = null;
+
+               int intIndex = cmdline.indexOf(" ");
+               if (intIndex == -1) {
+                       cmd = cmdline.toLowerCase();
+               } else {
+                       cmd = cmdline.substring(0, intIndex).toLowerCase();
+                       args = cmdline.substring(intIndex + 1).trim();
+               }
+
+               if (cmd.length() < 1) {
+                       return "huh?";
+               }
+
+               lt.isAlwaysCommands = true;
+               boolean blnFoundScriptedCommand = false;
+               /*
+                ** Don't try to find a scripted command if they are doing a tell
+                */
+               if (cmd.substring(0, 1) != "/") {
+                       try {
+                               Script script = new Script("commands/" + cmd, game, false);
+                               script.varVariables.addVariable("trigger", lt);
+                               if (args != null) {
+                                       script.runScript(args);
+                               } else {
+                                       script.runScript();
+                               }
+                               script.close();
+                               blnFoundScriptedCommand = true;
+                       } catch (Exception e) {
+                               blnFoundScriptedCommand = false;
+                       }
+                       if (!lt.isAlwaysCommands) {
+                               return null;
+                       }
+               }
+               if (lt.privs > 2) {
+                       if (cmdline.startsWith(">")) {
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               cmdline = cmdline.substring(1);
+                               if (cmdline.equalsIgnoreCase("s")) {
+                                       if (game.blnSavingGame) {
+                                               return "Game already being saved, please wait.";
+                                       }
+                                       game.saveMap();
+                                       return "Game settings saved";
+                               }
+
+                               String strMapLog = "shortmap_redraw";
+                               try (PrintStream psMap = new PrintStream(new FileOutputStream(strMapLog, true), true)) {
+                                       game.changeMap(lt.x, lt.y, Short.parseShort(cmdline));
+                                       psMap.println("changetile " + lt.x + " " + lt.y + " " + Short.parseShort(cmdline));
+                                       return null;
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While " + lt.name + " tried to >" + cmdline, e);
+                                       return null;
+                               }
+                       }
+                       if (cmdline.startsWith("<")) {
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               cmdline = cmdline.substring(1);
+                               if (cmdline.equals("s")) {
+                                       if (game.blnSavingGame) {
+                                               return "Game already being saved, please wait.";
+                                       }
+                                       game.saveMap();
+                                       return "Game settings saved";
+                               } else if (cmdline.equalsIgnoreCase("merchant")) {
+                                       if (game.overMerchant(lt.x, lt.y) != null) {
+                                               return "There's already a merchant there.";
+                                       }
+                                       if (game.overPlayerMerchant(lt.x, lt.y) != null) {
+                                               return "There's already a merchant there.";
+                                       }
+                                       Merchant mrcStore = new Merchant(game);
+                                       mrcStore.x = lt.x;
+                                       mrcStore.y = lt.y;
+                                       //game.vctMerchants.add(mrcStore);
+                                       //game.blnMerchantListChanged = true;
+                                       game.addDuskObject(mrcStore);
+                                       return null;
+                               } else if (cmdline.toLowerCase().startsWith("prop ")) {
+                                       if (cmdline.length() == 5) {
+                                               return "Add what prop?";
+                                       }
+                                       cmdline = cmdline.substring(5);
+                                       Prop prpStore = game.getProp(cmdline);
+                                       if (prpStore != null) {
+                                               prpStore.x = lt.x;
+                                               prpStore.y = lt.y;
+                                               //game.vctProps.addElement(prpStore);
+                                               //game.blnPropListChanged = true;
+                                               game.addDuskObject(prpStore);
+                                       }
+                                       return null;
+                               } else if (cmdline.startsWith("sign ")) {
+                                       if (cmdline.length() == 5) {
+                                               return "What should the sign say?";
+                                       }
+                                       Sign sgnStore = new Sign(game, "sign", cmdline.substring(5), lt.x, lt.y, game.getID());
+                                       //game.vctSigns.add(sgnStore);
+                                       //game.blnSignListChanged = true;
+                                       game.addDuskObject(sgnStore);
+                                       return null;
+                               }
+                               Item itmStore = game.getItem(cmdline);
+                               if (itmStore != null) {
+                                       itmStore.x = lt.x;
+                                       itmStore.y = lt.y;
+                                       //game.vctItems.add(itmStore);
+                                       game.addDuskObject(itmStore);
+                                       return null;
+                               }
+                               try {
+                                       Mob mob = new Mob(cmdline, lt.x, lt.y, game);
+                                       // TODO: this previously didn't call addDuskObject - bug or intentional?
+                                       //game.vctMobs.addElement(mob);
+                                       //game.blnMobListChanged = true;
+                                       game.addDuskObject(mob);
+
+                                       mob.changeLocBypass(lt.x, lt.y);
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While creating mob \"" + cmdline + "\"", e);
+                               }
+                               return null;
+                       }
+               }
+
+               // Remap shortcuts
+               if (cmd.startsWith(";")) {
+                       args = cmdline.substring(1).trim();
+                       cmd = "gossip";
+               }
+               if (cmd.startsWith(":")) {
+                       args = cmdline.substring(1).trim();
+                       cmd = "clan";
+               }
+               if (cmd.startsWith("'")) {
+                       args = cmdline.substring(1).trim();
+                       cmd = "say";
+               }
+               if (cmd.startsWith(".")) {
+                       args = cmdline.substring(1).trim();
+                       cmd = "emote";
+               }
+               if (cmd.startsWith("/")) {
+                       args = cmdline.substring(1).trim();
+                       cmd = "tell";
+               }
+
+               switch (cmd) {
+                       case "north":
+                       case "n":
+                               if (!lt.moveAfterClear("n")) {
+                                       return "You can't move while you're following someone.";
+                               }
+                               return null;
+                       case "south":
+                       case "s":
+                               if (!lt.moveAfterClear("s")) {
+                                       return "You can't move while you're following someone.";
+                               }
+                               return null;
+                       case "west":
+                       case "w":
+                               if (!lt.moveAfterClear("w")) {
+                                       return "You can't move while you're following someone.";
+                               }
+                               return null;
+                       case "east":
+                       case "e":
+                               if (!lt.moveAfterClear("e")) {
+                                       return "You can't move while you're following someone.";
+                               }
+                               return null;
+                       case "goto": {
+                               int destX;
+                               int destY;
+                               try {
+                                       destX = Integer.parseInt(args.substring(0, args.lastIndexOf(' ')));
+                                       destY = Integer.parseInt(args.substring(args.lastIndexOf(' ') + 1));
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():" + lt.name + " tried to " + cmdline, e);
+                                       return null;
+                               }
+                               return lt.goTo(destX, destY, true);
+                       }
+
+                       case "addmember": {
+                               if (lt.privs != 1)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Add who?";
+                               }
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world";
+                               }
+                               if (lt.battle != null) {
+                                       return "Not while you're fighting!";
+                               }
+                               if (thnStore.battle != null) {
+                                       thnStore.chatMessage(lt.name + " has invited you to join their clan, but you are in the middle of a battle");
+                                       return "They're in the middle of a battle. They have been notified that you tried to clan them.";
+                               }
+                               lt.chatMessage("You have invited " + thnStore.name + " to join the clan " + lt.clan + ".");
+
+                               if (true)
+                                       // FIXME: protocol implementation
+                                       throw new RuntimeException("cannot ask questions yet");
+                               // FIXME: this looks dodgy
+                               // FIXME: move to livingthing
+
+                               thnStore.halt();
+                               thnStore.stillThere();  // This puts something in the buffer
+                               thnStore.stillThere();  // Have to do this twice to ensure that thnStore is out of
+                               // its read loop
+                               lt.connectionThread.sleep(500);  // wait for the "notdead" response to get back from client.
+                               try {
+                                       // Empty out the BufferedReader for the answer
+                                       //      while (thnStore.instream.ready()) {
+                                       //              thnStore.instream.read();
+                                       //      }
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While " + lt.name + " was trying to addmember " + thnStore.name, e);
+                               }
+                               thnStore.chatMessage(lt.name + " has invited you to join the clan " + lt.clan + ". If you accept, type yes.");
+                               try {
+                                       if (thnStore.instream.readLine().equalsIgnoreCase("yes")) {
+                                               thnStore.clan = lt.clan;
+                                               if (thnStore.privs == 1) {
+                                                       thnStore.privs = 0;
+                                               }
+                                               thnStore.chatMessage("You have been added to the clan, " + lt.clan + "");
+                                               thnStore.proceed();
+                                               game.removeDuskObject(thnStore);
+                                               game.addDuskObject(thnStore);
+                                               return thnStore.name + " has accepted your invitation.";
+                                       }
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While reading the answer to " + lt.name + "'s attempt to addmember " + thnStore.name, e);
+                               }
+                               thnStore.proceed();
+                               return thnStore.name + " has declined your invitation.";
+                       }
+                       case "kick": {
+                               if (lt.privs != 1)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Kick who?";
+                               }
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               if (!thnStore.clan.equalsIgnoreCase(lt.clan)) {
+                                       return "They're not in your clan.";
+                               }
+                               thnStore.chatMessage("You have been kicked out of " + lt.clan + ".");
+                               thnStore.clan = "none";
+                               game.removeDuskObject(thnStore);
+                               game.addDuskObject(thnStore);
+                               return thnStore.name + " has been kicked out of your clan.";
+                       }
+//             if (lt.privs > 2) {
+//                     if (lt.privs > 4) {
+                       case "makegod": {
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args == null) {
+                                       return "Make who a god?";
+                               }
+                               int iSPloc = args.indexOf(" ");
+                               if (iSPloc < 0) {
+                                       return "Make them what level of a god?";
+                               }
+                               String sName = args.substring(0, iSPloc).trim();
+                               int level = Integer.parseInt(args.substring(iSPloc).trim());
+
+                               LivingThing thnStore = game.getPlayer(sName);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               int oldLevel = thnStore.privs;
+                               thnStore.privs = level;
+                               thnStore.isSaveNeeded = true;
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":Changed " + thnStore.name + "'s priveledges from " + oldLevel + " to " + level + ".");
+                               return thnStore.name + "'s priveledges have been set to " + level + ".";
+                       }
+                       case "reloadprefs": {
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.loadPrefs();
+                               return "Preferences reloaded";
+                       }
+                       case "resizemap":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.resizeMap(lt.x + 1, lt.y + 1);
+                               return "Map resized";
+                       case "shutdown":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.ALWAYS, lt.name + " has shut down the server.");
+                               game.chatMessage("The server is going down.", "default");
+                               game.blnShuttingDown = true;
+                               for (LivingThing thnStore : game.playersByName.values()) {
+                                       try {
+                                               if (thnStore != lt) {
+                                                       thnStore.close();
+                                               }
+                                       } catch (Exception e) {
+                                               if (thnStore != null) {
+                                                       game.log.printError("parseCommand():While trying to close " + thnStore.name + " for " + lt.name + "'s shutdown request", e);
+                                               } else {
+                                                       game.log.printError("parseCommand():While trying to close a null player for " + lt.name + "'s shutdown request", e);
+                                               }
+                                       }
+                               }
+                               lt.isSaveNeeded = true;
+                               lt.savePlayer();
+                               System.gc();
+                               System.exit(0);
+                               return null;
+                       case "stop":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.blnShuttingDown = true;
+                               return "Stopped accepting incoming socket connections.";
+                       case "start":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.blnShuttingDown = false;
+                               return "Started accepting incoming connections";
+                       case "filteron":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.blnIPF = true;
+                               return "Started filtering duplicate IP addressess of socket connections.";
+                       case "filteroff":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.blnIPF = false;
+                               return "Stopped filtering duplicate IP addressess of socket connections.";
+                       case "floodlimit":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args == null) {
+                                       return "What value do you want the floodlimit to have?";
+                               }
+                               try {
+                                       game.floodLimit = (long) Integer.parseInt(args);
+                                       return "Set floodlimit to " + args + " milliseconds.";
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():Invalid value \"" + args + "\" for floodlimit.", e);
+                                       return "Invalid value \"" + args + "\" for floodlimit.";
+                               }
+                       case "ipban": {
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               String strBlockedIP;
+                               if (args == null) {
+                                       return "Whos IP address do you wish to ban?";
+                               }
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               String strIP = thnStore.getAddress();
+                               int i = strIP.indexOf("/");
+                               strIP = strIP.substring(i + 1, strIP.length());
+                               // FIXME: better i/o
+                               try (RandomAccessFile rafBannedIP = new RandomAccessFile("conf/blockedIP", "rw")) {
+                                       strBlockedIP = rafBannedIP.readLine();
+                                       while (strBlockedIP != null) {
+                                               if (strIP.indexOf(strBlockedIP) != -1) {
+                                                       //rafBannedIP.close();
+                                                       return "Already blocked.";
+                                               }
+                                               strBlockedIP = rafBannedIP.readLine();
+                                       }
+                                       rafBannedIP.seek(rafBannedIP.length());
+                                       rafBannedIP.writeBytes(strIP + "\n");
+                               } catch (IOException ex) {
+                                       game.log.printError("parseCommand():When " + lt.name + " tried to ban " + thnStore + "'s IP address", ex);
+                               }
+                               return thnStore.name + "'s IP address has been blocked.";
+                       }
+                       case "loglevel":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args == null) {
+                                       return "Logging level is currently " + game.log.getLogLevel();
+                               }
+                               try {
+                                       int level = Integer.parseInt(args);
+                                       game.log.setLogLevel(level);
+                                       return "Logging level is now " + game.log.getLogLevel();
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():Invalid value \"" + args + "\" for loglevel.", e);
+                                       return "Invalid value \"" + args + "\" for loglevel.";
+                               }
+                       case "gc":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "Starting garbage collection.");
+                               System.gc();
+                               game.log.printMessage(Log.INFO, "Finished garbage collection.");
+                               return "Finished garbage collection.";
+                       case "finalize":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "Starting finalization.");
+                               System.runFinalization();
+                               game.log.printMessage(Log.INFO, "Finished finalization.");
+                               return "Finished finalization.";
+                       case "cleanup":
+                               if (lt.privs <= 4)
+                                       return "Huh?";
+                               game.cleanup();
+                               return "Finished cleanup.";
+                       case "save":
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (game.blnSavingGame) {
+                                       return "Game already being saved, please wait.";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.saveMap();
+                               return "Game settings saved";
+                       case "backup":
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.backupMap();
+                               return "Game settings backed up";
+                       case "list": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "What do you want to list?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               cmdline = cmdline.substring(5);
+                               String filename = null;
+                               String strTitle = null;
+                               if (args.equals("items")) {
+                                       filename = "defItems";
+                                       strTitle = "Items:\n";
+                               } else if (args.equals("conf")) {
+                                       filename = "conf";
+                                       strTitle = "Conf files:\n";
+                               } else if (args.equals("mobs")) {
+                                       filename = "defMobs";
+                                       strTitle = "Mobiles:\n";
+                               } else if (args.equals("commands")) {
+                                       filename = "commands";
+                                       strTitle = "Custom commands:\n";
+                               } else if (args.equals("races")) {
+                                       filename = "defRaces";
+                                       strTitle = "Races:\n";
+                               } else if (args.equals("pets")) {
+                                       filename = "defPets";
+                                       strTitle = "Pets:\n";
+                               } else if (args.equals("factions")) {
+                                       filename = "factions";
+                                       strTitle = "Factions:\n";
+                               } else if (args.equals("conditions")) {
+                                       filename = "defConditions";
+                                       strTitle = "Conditions:\n";
+                               } else if (args.equals("help")) {
+                                       filename = "helpFiles";
+                                       strTitle = "Help Files:\n";
+                               } else if (args.equals("scripts")) {
+                                       filename = "scripts";
+                                       strTitle = "Scripts:\n";
+                               } else if (args.equals("spell groups")) {
+                                       filename = "defSpellGroups";
+                                       strTitle = "Spell Groups:\n";
+                               } else if (args.equals("spells")) {
+                                       filename = "defSpells";
+                                       strTitle = "Spells:\n";
+                               } else if (args.equals("props")) {
+                                       filename = "defProps";
+                                       strTitle = "Props:\n";
+                               } else if (args.equals("move actions")) {
+                                       filename = "defMoveActions";
+                                       strTitle = "Move Action Scripts:\n";
+                               } else if (args.equals("can move")) {
+                                       filename = "defCanMoveScripts";
+                                       strTitle = "Can Move Scripts:\n";
+                               } else if (args.equals("can see")) {
+                                       filename = "defCanSeeScripts";
+                                       strTitle = "Can See Scripts:\n";
+                               } else if (args.equals("tile actions")) {
+                                       filename = "defTileActions";
+                                       strTitle = "Tile Action Scripts:\n";
+                               } else if (args.equals("tile move")) {
+                                       filename = "defTileScripts";
+                                       strTitle = "Can Move Tile Scripts:\n";
+                               } else if (args.equals("tile see")) {
+                                       filename = "defTileSeeScripts";
+                                       strTitle = "Tile See Scripts:\n";
+                               }
+                               if (filename != null) {
+                                       File filList = new File(filename);
+                                       String strResult[] = filList.list();
+                                       StringBuilder strBuff = new StringBuilder();
+                                       strBuff.append("").append((char) 20).append(strTitle).append("\n");
+                                       for (int i = 0; i < strResult.length; i++) {
+                                               // Only output files that do not end in .dsko
+                                               if (strResult[i].indexOf(".dsko") == -1) {
+                                                       strBuff.append(strResult[i]).append("\n");
+                                               }
+                                       }
+                                       strBuff.append("--EOF--\n");
+                                       lt.send(strBuff.toString());
+                                       return null;
+                               }
+                               return "You can't list that.";
+                       }
+                       case "view": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+
+                               if (args == null) {
+                                       return "What do you want to view?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args.indexOf("..") != -1) {
+                                       return "You don't have permission to access that file.";
+                               }
+                               String filename = null;
+                               boolean blnUser = false;
+                               boolean blnPet = false;
+                               if (args.startsWith("item ")) {
+                                       args = args.toLowerCase();
+                                       filename = "defItems/" + args.substring(5);
+                               } else if (args.startsWith("conf ")) {
+                                       filename = "conf/" + args.substring(5);
+                               } else if (args.startsWith("mob ")) {
+                                       filename = "defMobs/" + args.substring(4);
+                               } else if (args.startsWith("command ")) {
+                                       filename = "commands/" + args.substring(8);
+                               } else if (args.startsWith("race ")) {
+                                       filename = "defRaces/" + args.substring(5);
+                               } else if (args.startsWith("pet ")) {
+                                       filename = "defPets/" + args.substring(5);
+                               } else if (args.startsWith("faction")) {
+                                       return "You cannot view faction files.";
+                               } else if (args.startsWith("condition ")) {
+                                       filename = "defConditions/" + args.substring(10);
+                               } else if (args.startsWith("help ")) {
+                                       filename = "helpFiles/" + args.substring(5);
+                               } else if (args.startsWith("script ")) {
+                                       filename = "scripts/" + args.substring(7);
+                               } else if (args.startsWith("spell group ")) {
+                                       filename = "defSpellGroups/" + args.substring(12);
+                               } else if (args.startsWith("spell ")) {
+                                       filename = "defSpells/" + args.substring(6);
+                               } else if (args.startsWith("prop ")) {
+                                       filename = "defProps/" + args.substring(5);
+                               } else if (args.startsWith("move action ")) {
+                                       filename = "defMoveActions/" + args.substring(12);
+                               } else if (args.startsWith("can move ")) {
+                                       filename = "defCanMoveScripts/" + args.substring(9);
+                               } else if (args.startsWith("can see ")) {
+                                       filename = "defCanSeeScripts/" + args.substring(8);
+                               } else if (args.startsWith("tile action ")) {
+                                       filename = "defTileActions/" + args.substring(12);
+                               } else if (args.startsWith("tile move ")) {
+                                       filename = "defTileScripts/" + args.substring(10);
+                               } else if (args.startsWith("tile see ")) {
+                                       filename = "defTileSeeScripts/" + args.substring(9);
+                               } else if (args.startsWith("user ")) {
+                                       if (lt.privs < 5) {
+                                               return "You don't have enough privelages to edit a user's file.";
+                                       }
+                                       blnUser = true;
+                                       filename = "users/" + args.substring(5);
+                               } else if (args.startsWith("pet ")) {
+                                       if (lt.privs < 5) {
+                                               return "You don't have enough privelages to edit a user's pet file.";
+                                       }
+                                       blnPet = true;
+                                       filename = "pets/" + args.substring(4);
+                               }
+                               File filView = new File(filename);
+                               if (!filView.exists()) {
+                                       if (blnUser) {
+                                               return "There is no player named \"" + filView.getName() + "\".";
+                                       }
+                                       if (blnPet) {
+                                               return "The player named \"" + filView.getName() + "\" does not have a pet.";
+                                       }
+                                       lt.send((char) 18 + args + "\n--EOF--\n");
+                                       return null;
+                               }
+                               RandomAccessFile rafView = null;
+                               StringBuffer strBuff = new StringBuffer();
+                               try {
+                                       rafView = new RandomAccessFile(filView, "rw");
+                                       if (blnUser) {
+                                               rafView.readLine();  //Skip over users' password
+                                       }
+                                       String strStore2 = rafView.readLine();
+                                       strBuff.append((char) 18 + args + "\n");
+                                       while (strStore2 != null) {
+                                               strBuff.append(strStore2 + "\n");
+                                               strStore2 = rafView.readLine();
+                                       }
+                                       strBuff.append("--EOF--\n");
+                                       lt.send(strBuff.toString());
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():Reading file for " + filView.getName(), e);
+                               }
+                               try {
+                                       rafView.close();
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():Closing file after " + filView.getName(), e);
+                               }
+                               return null;
+                       }
+                       case "submit": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "What do you want to submit?";
+                               }
+                               if ((lt.privs < 4) && (!args.startsWith("mob "))) {
+                                       return "You are not allowed to submit files.";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args.indexOf("..") != -1) {
+                                       return "You don't have permission to access that file.";
+                               }
+                               boolean compile = false;
+                               boolean blnUser = false;
+                               boolean blnPet = false;
+                               String strFileName = null;
+                               if (args.startsWith("item ") && (lt.privs > 3)) {
+                                       args = args.toLowerCase();
+                                       strFileName = "defItems/" + args.substring(5);
+                               } else if (args.startsWith("conf ") && (lt.privs > 3)) {
+                                       strFileName = "conf/" + args.substring(5);
+                               } else if (args.startsWith("mob ")) {
+                                       strFileName = "defMobs/" + args.substring(4);
+                               } else if (args.startsWith("command ") && (lt.privs > 3)) {
+                                       strFileName = "commands/" + args.substring(8);
+                                       compile = true;
+                               } else if (args.startsWith("race ") && (lt.privs > 3)) {
+                                       strFileName = "defRaces/" + args.substring(5);
+                               } else if (args.startsWith("pet ") && (lt.privs > 3)) {
+                                       strFileName = "defPets/" + args.substring(4);
+                               } else if (args.startsWith("faction") && (lt.privs > 3)) {
+                                       return "You cannot submit faction files.";
+                               } else if (args.startsWith("condition ") && (lt.privs > 3)) {
+                                       strFileName = "defConditions/" + args.substring(10);
+                               } else if (args.startsWith("help ") && (lt.privs > 3)) {
+                                       strFileName = "helpFiles/" + args.substring(5);
+                               } else if (args.startsWith("script ") && (lt.privs > 3)) {
+                                       strFileName = "scripts/" + args.substring(7);
+                                       compile = true;
+                               } else if (args.startsWith("spell group ") && (lt.privs > 3)) {
+                                       strFileName = "defSpellGroups/" + args.substring(12);
+                                       compile = true;
+                               } else if (args.startsWith("spell ") && (lt.privs > 3)) {
+                                       strFileName = "defSpells/" + args.substring(6);
+                               } else if (args.startsWith("prop ")) {
+                                       strFileName = "defProps/" + args.substring(5);
+                               } else if (args.startsWith("move action ") && (lt.privs > 3)) {
+                                       strFileName = "defMoveActions/" + args.substring(12);
+                                       compile = true;
+                               } else if (args.startsWith("can move ") && (lt.privs > 3)) {
+                                       strFileName = "defCanMoveScripts/" + args.substring(9);
+                                       compile = true;
+                               } else if (args.startsWith("can see ") && (lt.privs > 3)) {
+                                       strFileName = "defCanSeeScripts/" + args.substring(8);
+                                       compile = true;
+                               } else if (args.startsWith("tile action ") && (lt.privs > 3)) {
+                                       strFileName = "defTileActions/" + args.substring(12);
+                                       compile = true;
+                               } else if (args.startsWith("tile move ") && (lt.privs > 3)) {
+                                       strFileName = "defTileScripts/" + args.substring(10);
+                                       compile = true;
+                               } else if (args.startsWith("tile see ") && (lt.privs > 3)) {
+                                       strFileName = "defTileSeeScripts/" + args.substring(9);
+                                       compile = true;
+                               } else if (args.startsWith("user ")) {
+                                       if (lt.privs < 5) {
+                                               return "You don't have enough privelages to submit a user's file.";
+                                       }
+                                       if (game.getPlayer(args.substring(5)) != null) {
+                                               return "You cannot submit a file for an active user.";
+                                       }
+                                       blnUser = true;
+                                       strFileName = "users/" + args.substring(5);
+                               } else if (args.startsWith("pet ")) {
+                                       if (lt.privs < 5) {
+                                               return "You don't have enough privelages to submit a user's pet file.";
+                                       }
+                                       if (game.getPlayer(args.substring(4)) != null) {
+                                               return "You cannot submit a pet file for an active user.";
+                                       }
+                                       blnPet = true;
+                                       strFileName = "pets/" + args.substring(4);
+                               }
+                               if (strFileName == null) {
+                                       return "Cannot submit " + args;
+                               }
+                               File filView = null;
+                               try {
+                                       filView = new File(strFileName);
+                               } catch (Exception e) {
+                                       return "Cannot submit " + args + " (" + strFileName + ")";
+                               }
+                               RandomAccessFile rafView = null;
+                               try {
+                                       if (blnUser) {
+                                               /*
+                                                Read in the user's password before deleting the file
+                                                */
+                                               rafView = new RandomAccessFile(filView, "r");
+                                               cmdline = rafView.readLine();
+                                       }
+                                       if (filView.exists()) {
+                                               filView.delete();
+                                       }
+                                       rafView = new RandomAccessFile(filView, "rw");
+                                       if (blnUser) {
+                                               /*
+                                                Write out the password for user files
+                                                */
+                                               rafView.writeBytes(cmdline + "\n");
+                                       }
+                                       cmdline = lt.instream.readLine();
+                                       while (!cmdline.equals("--EOF--")) {
+                                               rafView.writeBytes(cmdline + "\n");
+                                               cmdline = lt.instream.readLine();
+                                       }
+                                       rafView.close();
+                                       if (compile) {
+                                               Script scrStore = new Script(filView.getPath(), game, true);
+                                               scrStore.close();
+                                       }
+                                       if (blnUser || blnPet) {
+                                               /*
+                                                Delete the .backup file for users and pets
+                                                */
+                                               filView = new File(strFileName + ".backup");
+                                               if (filView.exists()) {
+                                                       filView.delete();
+                                               }
+                                       }
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While submitting file " + args + " (" + filView.getName() + ")", e);
+                                       try {
+                                               rafView.close();
+                                       } catch (Exception e2) {
+                                               game.log.printError("parseCommand():While closing file " + args + " (" + filView.getName() + ") after failed submit", e);
+                                       }
+                                       return "Error while trying to submit " + args + " (" + filView.getName() + ").";
+                               }
+                               return "Submit of " + args + " was successful.";
+                       }
+                       case "delete": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "What do you want to delete?";
+                               }
+                               if (lt.privs < 4) {
+                                       return "You are not allowed to delete files.";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               if (args.indexOf("..") != -1) {
+                                       return "You don't have permission to access that file.";
+                               }
+                               String filename = null;
+                               String strReturn = null;
+                               if (args.startsWith("item ")) {
+                                       filename = "defItems/" + args.substring(5);
+                                       strReturn = "item " + args.substring(5);
+                               } else if (args.startsWith("conf ")) {
+                                       filename = "conf/" + args.substring(5);
+                                       strReturn = "conf " + args.substring(5);
+                               } else if (args.startsWith("mob ")) {
+                                       filename = "defMobs/" + args.substring(4);
+                                       strReturn = "mob " + args.substring(4);
+                               } else if (args.startsWith("command ")) {
+                                       filename = "commands/" + args.substring(8);
+                                       strReturn = "command " + args.substring(8);
+                               } else if (args.startsWith("race ")) {
+                                       filename = "defRaces/" + args.substring(5);
+                                       strReturn = "race " + args.substring(5);
+                               } else if (args.startsWith("pet ")) {
+                                       filename = "defPets/" + args.substring(4);
+                                       strReturn = "pet " + args.substring(4);
+                               } else if (args.startsWith("faction")) {
+                                       return "You cannot delete faction files.";
+                               } else if (args.startsWith("condition ")) {
+                                       filename = "defConditions/" + args.substring(8);
+                                       strReturn = "condition " + args.substring(8);
+                               } else if (args.startsWith("help ")) {
+                                       filename = "helpFiles/" + args.substring(5);
+                                       strReturn = "help " + args.substring(5);
+                               } else if (args.startsWith("script ")) {
+                                       filename = "scripts/" + args.substring(7);
+                                       strReturn = "script " + args.substring(7);
+                               } else if (args.startsWith("spell group ")) {
+                                       filename = "defSpellGroups/" + args.substring(12);
+                                       strReturn = "spell group " + args.substring(12);
+                               } else if (args.startsWith("spell ")) {
+                                       filename = "defSpells/" + args.substring(6);
+                                       strReturn = "spell " + args.substring(6);
+                               } else if (args.startsWith("prop ")) {
+                                       filename = "defProps/" + args.substring(5);
+                                       strReturn = "prop " + args.substring(5);
+                               } else if (args.startsWith("move action ")) {
+                                       filename = "defMoveActions/" + args.substring(12);
+                                       strReturn = "move action " + args.substring(12);
+                               } else if (args.startsWith("can move ")) {
+                                       filename = "defCanMoveScripts/" + args.substring(9);
+                                       strReturn = "can move " + args.substring(9);
+                               } else if (args.startsWith("can see ")) {
+                                       filename = "defCanSeeScripts/" + args.substring(8);
+                                       strReturn = "can see " + args.substring(8);
+                               } else if (args.startsWith("tile action ")) {
+                                       filename = "defTileActions/" + args.substring(12);
+                                       strReturn = "tile action " + args.substring(12);
+                               } else if (args.startsWith("tile move ")) {
+                                       filename = "defTileScripts/" + args.substring(10);
+                                       strReturn = "tile move " + args.substring(10);
+                               } else if (args.startsWith("tile see ")) {
+                                       filename = "defTileSeeScripts/" + args.substring(9);
+                                       strReturn = "tile see " + args.substring(9);
+                               }
+                               File filDelete = null;
+                               if (filename != null) {
+                                       filDelete = new File(filename);
+                                       if (filDelete.exists()) {
+                                               filDelete.delete();
+                                               filDelete = new File(filename + ".dsko");
+                                               if (filDelete.exists()) {
+                                                       filDelete.delete();
+                                                       strReturn += " and the associated .dsko file.";
+                                               }
+                                       } else {
+                                               return strReturn + " does not exist.";
+                                       }
+                                       return "Deleted " + strReturn;
+                               }
+                               return "You cannot delete that.";
+                       }
+                       case "clanleader": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+
+                               if (args == null) {
+                                       return "Clanleader who?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               LivingThing thnStore = game.getPlayer(args.substring(0, args.indexOf(' ')));
+                               if (thnStore == null) {
+                                       return "They're not in this world";
+                               }
+                               if (args.length() < thnStore.name.length() + 2) {
+                                       return "What clan?";
+                               }
+                               if (thnStore.privs > 1) {
+                                       return "You can't clanleader them.";
+                               }
+                               args = args.substring(thnStore.name.length() + 1);
+                               thnStore.clan = args;
+                               if (args.equals("none")) {
+                                       thnStore.privs = 0;
+                                       thnStore.chatMessage("You are now clanless.");
+                               } else {
+                                       thnStore.privs = 1;
+                                       thnStore.chatMessage("You are now a member of the " + args + " clan.");
+                               }
+                               game.removeDuskObject(thnStore);
+                               game.addDuskObject(thnStore);
+                               return thnStore.name + " is now a leader of the " + args + " clan.";
+                       }
+                       case "boot": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Boot who?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               if (thnStore.privs >= lt.privs) {
+                                       thnStore.chatMessage(lt.name + " attempted to boot you.");
+                                       return "You do not have high enough privelages to boot them.";
+                               }
+                               thnStore.chatMessage("You have been booted.");
+                               thnStore.close();
+                               return null;
+                       }
+                       case "hardkill": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "HardKill who?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               if (thnStore.privs >= lt.privs) {
+                                       thnStore.chatMessage(lt.name + " attempted to HardKill you.");
+                                       return "You do not have high enough privelages to HardKill them.";
+                               }
+                               thnStore.closeNoMsgPlayer();
+                               return null;
+                       }
+                       case "nochannel": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "nochannel who for how long?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               LivingThing thnStore;
+                               int duration;
+                               try {
+                                       thnStore = game.getPlayer(args.substring(0, args.indexOf(" ")));
+                                       duration = Integer.parseInt(args.substring(args.indexOf(" ") + 1));
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():When " + lt.name + " tried to nochannel " + args, e);
+                                       return "nochannel who for how long?";
+                               }
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               if (thnStore.privs >= lt.privs) {
+                                       thnStore.chatMessage(lt.name + " attempted to nochannel you.");
+                                       return "You do not have high enough privelages to nochannel them.";
+                               }
+                               if (duration > game.noChannelMax) {
+                                       duration = game.noChannelMax;
+                               }
+                               thnStore.chatMessage("You have been nochanneled for " + duration + " seconds.");
+                               thnStore.noChannel = duration;
+                               return "You have nochanneled " + thnStore.name + " for " + duration + " seconds";
+                       }
+                       case "allowchannel": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "allowchannel who?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               thnStore.chatMessage("Your nochannel status has been removed.");
+                               thnStore.noChannel = 0;
+                               return thnStore.name + "'s nochannel status has been removed.";
+                       }
+                       case "gecho": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "G-Echo what?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               game.chatMessage(args, "default");
+                               return null;
+                       }
+                       case "teleport": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Teleport to where?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               int index = args.lastIndexOf('_');
+                               char charSep = ' ';
+                               if (index != -1) {
+                                       charSep = '_';
+                               }
+                               try {
+                                       int destX = Integer.parseInt(args.substring(0, args.lastIndexOf(charSep)));
+                                       int destY = Integer.parseInt(args.substring(args.lastIndexOf(charSep) + 1));
+                                       if (lt.privs < 5 && destX >= game.map.getCols()) {
+                                               destX = game.map.getCols() - 1;
+                                       }
+                                       if (lt.privs < 5 && destY >= game.map.getRows()) {
+                                               destY = game.map.getRows() - 1;
+                                       }
+                                       if (destX < 0) {
+                                               destX = 0;
+                                       }
+                                       if (destY < 0) {
+                                               destY = 0;
+                                       }
+                                       lt.changeLocBypass(destX, destY);
+                               } catch (Exception e) {
+                                       LivingThing thnStore = game.getPlayer(args);
+                                       if (thnStore == null) {
+                                               return "Teleport to where?";
+                                       } else {
+                                               int destX = thnStore.x;
+                                               int destY = thnStore.y;
+                                               if (lt.privs < 5 && destX > 349) {
+                                                       destX = 349;
+                                               }
+                                               if (lt.privs < 5 && destY > 349) {
+                                                       destY = 349;
+                                               }
+                                               if (destX < 0) {
+                                                       destX = 0;
+                                               }
+                                               if (destY < 0) {
+                                                       destY = 0;
+                                               }
+                                               lt.changeLocBypass(destX, destY);
+                                       }
+                               }
+                               return null;
+                       }
+                       case "remove": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "remove what?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               DuskObject objStore = lt.getLocalObject(args);
+                               if (objStore != null) {
+                                       if (objStore.isLivingThing()) {
+                                               LivingThing thnStore = (LivingThing) objStore;
+                                               if (thnStore.isMob()) {
+                                                       thnStore.close();
+                                                       game.blnMobListChanged = true;
+                                                       return "Object removed.";
+                                               } else {
+                                                       return "You can't remove players/pets.";
+                                               }
+                                       } else if (objStore.isItem()) {
+                                               //game.vctItems.remove(objStore);
+                                               game.removeDuskObject(objStore);
+                                               return "Object removed.";
+                                       } else if (objStore.isSign()) {
+                                               //game.vctSigns.remove(objStore);
+                                               //game.blnSignListChanged = true;
+                                               game.removeDuskObject(objStore);
+                                               return "Object removed.";
+                                       } else if (objStore.isProp()) {
+                                               //game.vctProps.removeElement(objStore);
+                                               //game.blnPropListChanged = true;
+                                               game.removeDuskObject(objStore);
+                                               return "Object removed.";
+                                       } else if (objStore.isMerchant()) {
+                                               //game.vctMerchants.remove(objStore);
+                                               //game.blnMerchantListChanged = true;
+                                               game.removeDuskObject(objStore);
+                                               return "Object removed.";
+                                       }
+                               }
+                               return "You don't see that here.";
+                       }
+                       case "changeclan": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "ChangeClan who?";
+                               }
+                               LivingThing thnStore = game.getPlayer(args.substring(0, args.indexOf(' ')));
+                               if (thnStore == null) {
+                                       return "They're not in this world";
+                               }
+                               if (cmdline.length() < thnStore.name.length() + 2) {
+                                       return "What clan?";
+                               }
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                               args = args.substring(thnStore.name.length() + 1);
+                               thnStore.clan = args;
+                               if (thnStore.privs == 1) {
+                                       thnStore.privs = 0;
+                               }
+                               if (args.equals("none")) {
+                                       thnStore.chatMessage("You are now a member of no clan.");
+                               } else {
+                                       thnStore.chatMessage("You are now a member of the " + args + " clan.");
+                               }
+                               return thnStore.name + " has been added to the " + args + " clan";
+                       }
+                       case "madd": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Madd what?";
+                               }
+                               Merchant mrcStore = game.overMerchant(lt.x, lt.y);
+                               if (mrcStore != null) {
+                                       game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                                       mrcStore.items.add(args);
+                                       game.refreshEntities(lt);
+                               } else {
+                                       if (game.overPlayerMerchant(lt.x, lt.y) != null) {
+                                               return "You cannot add items to a player's merchant this way.";
+                                       }
+                                       return "You are not on a merchant.";
+                               }
+                               return null;
+                       }
+                       case "mremove": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               if (args == null) {
+                                       return "Mremove what?";
+                               }
+                               Merchant mrcStore = game.overMerchant(lt.x, lt.y);
+                               if (mrcStore != null) {
+                                       game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+                                       mrcStore.items.remove(args);
+                                       game.refreshEntities(lt);
+                               } else {
+                                       if (game.overPlayerMerchant(lt.x, lt.y) != null) {
+                                               return "You cannot remove items from a player's merchant this way.";
+                                       }
+                                       return "You are not on a merchant.";
+                               }
+                               return null;
+                       }
+                       case "whoip": {
+                               if (lt.privs <= 2)
+                                       return "Huh?";
+                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":" + cmdline + ":" + lt.x + "," + lt.y);
+
+                               int nPlayers = game.playersByName.size();
+                               StringBuilder sb = new StringBuilder();
+
+                               // TODO: this used to be atomic, does it need to be?
+
+                               for (LivingThing thnStore : game.playersByName.values()) {
+                                       boolean hidden = false;
+                                       if (thnStore.privs > 2) {
+                                               if (thnStore.hasCondition("invis")) {
+                                                       hidden = true;
+                                               }
+                                       }
+                                       if (hidden && (lt.privs < thnStore.privs)) {
+                                               nPlayers--;
+                                       }
+                               }
+
+                               lt.chatMessage("\tThere are " + nPlayers + " players online:");
+
+                               for (LivingThing thnStore : game.playersByName.values()) {
+                                       boolean hidden = false;
+                                       boolean skip = false;
+                                       if (thnStore.privs > 2) {
+                                               if (thnStore.hasCondition("invis")) {
+                                                       hidden = true;
+                                               }
+                                       }
+                                       if (hidden && (lt.privs < thnStore.privs)) {
+                                               skip = true;
+                                       }
+                                       if (!skip) {
+                                               String ip = thnStore.getAddress().toString();
+                                               while (ip.length() < 34) {
+                                                       ip += " ";
+                                               }
+                                               sb.setLength(0);
+                                               sb.append("   ").append(ip);
+                                               sb.append(thnStore.getCharacterPoints()).append("cp ");
+                                               if (thnStore.privs == 1) {
+                                                       sb.append("{Clan Leader}");
+                                               } else if (thnStore.privs == 3) {
+                                                       sb.append("{God}");
+                                               } else if (thnStore.privs == 4) {
+                                                       sb.append("{High God}");
+                                               } else if (thnStore.privs > 4) {
+                                                       sb.append("{Master God}");
+                                               }
+                                               if (hidden) {
+                                                       sb.append("{hidden}");
+                                               }
+                                               if (thnStore.noChannel != 0) {
+                                                       sb.append("{nochanneled}");
+                                               }
+                                               if (!thnStore.clan.equals("none")) {
+                                                       sb.append("<" + thnStore.clan + "> ");
+                                               }
+                                               sb.append(thnStore.name + "\n");
+                                               lt.chatMessage(sb.toString());
+                                       }
+                               }
+
+                               return null;
+                       }
+                       case "flee": {
+                               if (lt.battle != null) {
+                                       lt.battle.addFirstCommand(lt, "flee");
+                                       return null;
+                               } else {
+                                       return "You're not fighting anyone";
+                               }
+                       }
+                       case "sleep": {
+                               if (lt.isSleeping) {
+                                       return "You are already asleep";
+                               }
+                               if (lt.battle != null) {
+                                       return "Not while you're fighting!";
+                               }
+                               if (!(lt.getMaster() == null || lt.getMaster().isSleeping)) {
+                                       return "You can't sleep if you're following someone who's awake.";
+                               }
+                               lt.isSleeping = true;
+                               lt.updateActions();
+                               game.removeDuskObject(lt);
+                               game.addDuskObject(lt);
+                               return "You go to sleep";
+                       }
+                       case "wake": {
+                               if (lt.isSleeping) {
+                                       lt.isSleeping = false;
+                                       lt.updateActions();
+                                       game.removeDuskObject(lt);
+                                       game.addDuskObject(lt);
+                                       return "You wake up";
+                               } else {
+                                       return "You are already awake";
+                               }
+                       }
+                       case "change": {
+                               if (lt.battle != null) {
+                                       return "Not while you're fighting!";
+                               }
+                               if (args == null) {
+                                       return "Change what?";
+                               }
+                               if (args.equals("race")) {
+                                       if (lt.getCharacterPoints() > game.changeRaceCpLimit) {
+                                               return "You can no longer change your race.";
+                                       }
+                                       lt.unloadRace();
+
+                                       // FIXME: I'm not sure why this needs to clear messages here.
+
+                                       if (lt.isPet()) {
+
+                                               lt.getMaster().halt();
+                                               //                                      lt.getMaster().stillThere();  // This puts something in the buffer
+                                               //                                      lt.getMaster().thrConnection.sleep(750);  // wait for it...
+                                               try {
+                                                       // Empty out the BufferedReader for the answer
+                                                       //      while (lt.getMaster().instream.ready()) {
+                                                       //              lt.getMaster().instream.readLine();
+                                                       //      }
+                                               } catch (Exception e) {
+                                                       game.log.printError("parseCommand():Trying to empty ready buffer of pet's master for change race.", e);
+                                               }
+                                       } else {
+                                               lt.halt();
+                                               //                                      lt.stillThere();  // This puts something in the buffer
+                                               //                                      lt.thrConnection.sleep(750);  // wait for it...
+                                               try {
+                                                       // Empty out the BufferedReader for the answer
+                                                       //      while (lt.instream.ready()) {
+                                                       //              lt.instream.readLine();
+                                                       //      }
+                                               } catch (Exception e) {
+                                                       game.log.printError("parseCommand():Trying to empty ready buffer of player for change race.", e);
+                                               }
+                                       }
+                                       lt.loadRace();
+                                       if (lt.isPet()) {
+                                               lt.getMaster().proceed();
+                                               lt.getMaster().updateStats();
+                                       } else {
+                                               lt.proceed();
+                                       }
+                                       game.removeDuskObject(lt);
+                                       game.addDuskObject(lt);
+                                       lt.updateStats();
+                                       return "Your race has been changed.";
+                               }
+                       }
+                       case "gossip": {
+                               if (!lt.isPlayer()) {
+                                       return "Only players can use the gossip/clan/tell channels.";
+                               }
+                               if (lt.noChannel != 0) {
+                                       return "You can't do that when nochanneled.";
+                               }
+                               if (args == null) {
+                                       return "Gossip what?";
+                               }
+                               if (args.length() > game.messagecap) {
+                                       return "That message was too long.";
+                               }
+                               if (!args.equals("")) {
+                                       long lTemp = lt.lastMessageStamp;
+                                       lt.lastMessageStamp = System.currentTimeMillis();
+                                       if ((System.currentTimeMillis() - lTemp) < game.floodLimit) {
+                                               return "No flooding.";
+                                       }
+                                       String strPerson = lt.name;
+                                       if (lt.privs > 2
+                                                       && lt.hasCondition("invis")
+                                                       && lt.hasCondition("invis2")) {
+                                               strPerson = "A god";
+                                       }
+                                       game.chatMessage(strPerson + " gossips: " + args, lt.name);
+                               }
+                               return null;
+                       }
+                       case "clan": {
+                               if (!lt.isPlayer() && !lt.isMob()) {
+                                       return "Only players can use the gossip/clan/tell channels.";
+                               }
+                               if (lt.clan.equals("none")) {
+                                       return "You're not in a clan. Use gossip instead";
+                               }
+                               if (lt.noChannel != 0) {
+                                       return "You can't do that when nochanneled.";
+                               }
+                               if (args == null) {
+                                       return "Clan what?";
+                               }
+                               if (args.length() > game.messagecap) {
+                                       return "That message was too long.";
+                               }
+                               if (!args.equals("")) {
+                                       long lTemp = lt.lastMessageStamp;
+                                       lt.lastMessageStamp = System.currentTimeMillis();
+                                       if ((System.currentTimeMillis() - lTemp) < game.floodLimit) {
+                                               return "No flooding.";
+                                       }
+                                       game.chatMessage(lt.name + " clans: " + args, lt.clan, lt.name);
+                               }
+                               return null;
+                       }
+                       case "say": {
+                               if (args == null) {
+                                       return "Say what?";
+                               }
+                               if (lt.noChannel != 0) {
+                                       return "You can't do that when nochanneled.";
+                               }
+                               if (args.length() > game.messagecap) {
+                                       return "That message was too long.";
+                               }
+                               if (!args.equals("")) {
+                                       if (lt.isPet()) {
+                                               game.chatMessage("Pet " + lt.name + " says: " + args, lt.x, lt.y, lt.name);
+                                       } else if (lt.isMob()) {
+                                               game.chatMessage("Mob " + lt.name + " says: " + args, lt.x, lt.y, "default");
+                                       } else {
+                                               long lTemp = lt.lastMessageStamp;
+                                               lt.lastMessageStamp = System.currentTimeMillis();
+                                               if ((System.currentTimeMillis() - lTemp) < game.floodLimit) {
+                                                       return "No flooding.";
+                                               }
+                                               String strPerson = lt.name;
+                                               if (lt.privs > 2
+                                                               && lt.hasCondition("invis")
+                                                               && lt.hasCondition("invis2")) {
+                                                       strPerson = "A god";
+                                               }
+                                               game.chatMessage(strPerson + " says: " + args, lt.x, lt.y, lt.name);
+                                       }
+                               }
+                               return null;
+                       }
+                       case "emote": {
+                               if (args == null) {
+                                       return "Emote what?";
+                               }
+                               if (lt.noChannel != 0) {
+                                       return "You can't do that when nochanneled.";
+                               }
+                               if (args.length() > game.messagecap) {
+                                       return "That message was too long.";
+                               }
+                               if (!args.equals("")) {
+                                       long lTemp = lt.lastMessageStamp;
+                                       lt.lastMessageStamp = System.currentTimeMillis();
+                                       if ((System.currentTimeMillis() - lTemp) < game.floodLimit) {
+                                               return "No flooding.";
+                                       }
+                                       String strPerson = lt.name;
+                                       if (lt.privs > 2
+                                                       && lt.hasCondition("invis")
+                                                       && lt.hasCondition("invis2")) {
+                                               strPerson = "A god";
+                                       }
+                                       game.chatMessage(strPerson + " " + args, lt.x, lt.y, lt.name);
+                               }
+                               return null;
+                       }
+                       case "tell": {
+                               if (!lt.isPlayer()) {
+                                       return "Only players can use the gossip/clan/tell channels.";
+                               }
+                               if (args == null) {
+                                       return "Tell who what?";
+                               }
+                               if (lt.noChannel != 0) {
+                                       return "You can't do that when nochanneled.";
+                               }
+                               StringTokenizer tknStore = new StringTokenizer(args, " ");
+                               String strStore2 = null;
+                               try {
+                                       strStore2 = tknStore.nextToken();
+                               } catch (Exception e) {
+                                       return "Tell who?";
+                               }
+                               LivingThing thnStore = game.getPlayer(strStore2);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               if (thnStore.privs > 2
+                                               && thnStore.hasCondition("invis")
+                                               && thnStore.hasCondition("invis2")) {
+                                       return "They're not in this world.";
+                               }
+                               if (thnStore.name.equalsIgnoreCase(lt.name)) {
+                                       return "Talking to yourself is not a good sign.";
+                               }
+                               String strIgnoreName = thnStore.name.toLowerCase();
+                               if (lt.ignoreList.contains(strIgnoreName)) {
+                                       return "You can't do that while you are ignoring them.";
+                               }
+                               strIgnoreName = lt.name.toLowerCase();
+                               if (thnStore.ignoreList.contains(strIgnoreName)) {
+                                       return "They did not get the message, they are ignoring you.";
+                               }
+                               args = args.substring(strStore2.length(), args.length()).trim();
+                               if (args.length() > game.messagecap) {
+                                       return "That message was too long.";
+                               }
+                               if (args.length() == 0) {
+                                       return "Tell them what?";
+                               }
+                               long lTemp = lt.lastMessageStamp;
+                               lt.lastMessageStamp = System.currentTimeMillis();
+                               if ((System.currentTimeMillis() - lTemp) < game.floodLimit) {
+                                       return "No flooding.";
+                               }
+                               String strPerson = lt.name;
+                               if (lt.privs > 2
+                                               && lt.hasCondition("invis")
+                                               && lt.hasCondition("invis2")) {
+                                       strPerson = "A god";
+                               }
+                               game.log.printMessage(Log.ALWAYS, lt.name + " tells " + thnStore.name + " : " + args);
+                               thnStore.chatMessage(strPerson + " tells you: " + args);
+                               return "You tell " + strStore2 + ": " + args;
+                       }
+                       case "who": {
+                               int nPlayers = game.playersByName.size();
+                               StringBuilder sb = new StringBuilder();
+
+                               // TOOD: originally this was atomic on stream
+                               // although 'atomic' is wrong since nobody else was atomic on stream
+
+                               for (LivingThing thnStore : game.playersByName.values()) {
+                                       boolean hidden = false;
+                                       if (thnStore.privs > 2) {
+                                               if (thnStore.hasCondition("invis")) {
+                                                       hidden = true;
+                                               }
+                                       }
+                                       if (hidden && (lt.privs < thnStore.privs)) {
+                                               nPlayers--;
+                                       }
+                                       if (lt.privs < 3 && !thnStore.isWorking) {
+                                               nPlayers--;
+                                       }
+                                       if (lt.privs < 3 && !thnStore.isReady) {
+                                               nPlayers--;
+                                       }
+                               }
+
+                               lt.chatMessage("\tThere are " + nPlayers + " players online:");
+
+                               for (LivingThing thnStore : game.playersByName.values()) {
+                                       boolean hidden = false;
+                                       boolean skip = false;
+                                       if (thnStore.privs > 2) {
+                                               if (thnStore.hasCondition("invis")) {
+                                                       hidden = true;
+                                               }
+                                       }
+                                       if (hidden && (lt.privs < thnStore.privs)) {
+                                               skip = true;
+                                       }
+                                       if (lt.privs < 3 && !thnStore.isWorking) {
+                                               skip = true;
+                                       }
+                                       if (lt.privs < 3 && !thnStore.isReady) {
+                                               skip = true;
+                                       }
+                                       System.out.println(" user " + thnStore.name + " skip " + skip);
+                                       if (!skip) {
+                                               sb.setLength(0);
+                                               sb.append("\t");
+                                               sb.append(thnStore.getCharacterPoints());
+                                               sb.append("cp ");
+                                               if (lt.privs > 2 && !thnStore.isWorking) {
+                                                       sb.append("{* Not Working *}");
+                                               }
+                                               if (lt.privs > 2 && !thnStore.isReady) {
+                                                       sb.append("{Entering the world}");
+                                               }
+                                               if (lt.privs > 2 && !thnStore.isSaveable) {
+                                                       sb.append("{Loading/Saving}");
+                                               }
+                                               if (thnStore.privs == 1) {
+                                                       sb.append("{Clan Leader}");
+                                               } else if (thnStore.privs == 3) {
+                                                       sb.append("{God}");
+                                               } else if (thnStore.privs == 4) {
+                                                       sb.append("{High God}");
+                                               } else if (thnStore.privs > 4) {
+                                                       sb.append("{Master God}");
+                                               }
+                                               if (hidden) {
+                                                       sb.append("{hidden}");
+                                               }
+                                               if (thnStore.noChannel != 0) {
+                                                       sb.append("{nochanneled}");
+                                               }
+                                               if (thnStore.ignoreList.contains(lt.name.toLowerCase())) {
+                                                       sb.append("{Ignoring you}");
+                                               }
+                                               if (lt.ignoreList.contains(thnStore.name.toLowerCase())) {
+                                                       sb.append("{Ignored}");
+                                               }
+                                               if (!thnStore.clan.equals("none")) {
+                                                       sb.append("<");
+                                                       sb.append(thnStore.clan);
+                                                       sb.append("> ");
+                                               }
+                                               if (thnStore.title == null
+                                                               || thnStore.title.equals("none")) {
+                                                       sb.append(thnStore.name);
+                                                       //sb.append("\n");
+                                               } else {
+                                                       sb.append(thnStore.name);
+                                                       sb.append(" ");
+                                                       sb.append(thnStore.title);
+                                                       //sb.append("\n");
+                                               }
+                                               lt.chatMessage(sb.toString());
+                                       }
+                               }
+                               return "Who complete.";
+                       }
+                       case "kill":
+                       case "attack":
+                       case "a": {
+                               if (args == null) {
+                                       return "Attack what?";
+                               }
+                               if (lt.isSleeping) {
+                                       return "You can't do that while you're sleeping";
+                               }
+                               DuskObject objStore = lt.getLocalObject(args);
+                               if (objStore == null) {
+                                       return "You don't see that here.";
+                               }
+                               if (!objStore.isLivingThing()) {
+                                       return "You can't fight that.";
+                               }
+                               game.newBattle(lt, (LivingThing) objStore);
+                               return null;
+                       }
+                       case "order": {
+                               if (args == null) {
+                                       return "Order who to do what?";
+                               }
+                               int intStore = args.indexOf(" ");
+                               if (intStore == -1) {
+                                       return "Order them to do what?";
+                               }
+                               DuskObject objStore = lt.getLocalObject(args.substring(0, intStore));
+                               if (objStore == null) {
+                                       return "You don't see that here.";
+                               }
+                               if (!objStore.isLivingThing()) {
+                                       return "You can't order that.";
+                               }
+                               LivingThing thnStore = (LivingThing) objStore;
+                               if (thnStore.getCharmer() != lt) {
+                                       return "They don't take orders from you.";
+                               }
+                               args = args.substring(intStore + 1);
+                               try {
+                                       thnStore.chatMessage(Commands.parseCommand(thnStore, game, args));
+//                             lt.chatMessage(Commands.parseCommand(thnStore, engGame, strArgs));
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():" + thnStore.name + ", while trying to follow the following order: \"" + args + "\"", e);
+                               }
+                               return null;
+                       }
+
+                       case "look": {
+                               if (args == null) {
+                                       return "Look at what?";
+                               }
+                               if (lt.isSleeping) {
+                                       return "You can't do that while you're sleeping";
+                               }
+                               DuskObject objStore = lt.getLocalObject(args);
+                               if (objStore != null) {
+                                       if (objStore.isLivingThing()) {
+                                               LivingThing thnStore = (LivingThing) objStore;
+                                               thnStore.chatMessage(lt.name + " is looking at you.");
+                                               lt.chatMessage(thnStore.name + " has " + thnStore.getCharacterPoints() + "cp and " + thnStore.hp + "/" + thnStore.maxhp + "hp.");
+                                               if (thnStore.description != null) {
+                                                       lt.chatMessage("Their description is: " + thnStore.description);
+                                               }
+                                               final String[] formats = {
+                                                       "They are wielding %s.",
+                                                       "They are wearing %s on their arms.",
+                                                       "They are wearing %s on their legs.",
+                                                       "They are wearing %s on their torso.",
+                                                       "They are wearing %s on their waist.",
+                                                       "They are wearing %s on their neck.",
+                                                       "They are wearing %s on their skull.",
+                                                       "They are wearing %s on their eyes.",
+                                                       "They are wearing %s on their hands."
+                                               };
+                                               for (int i = 0; i < formats.length; i++) {
+                                                       Item item = thnStore.wornItems.getWorn(i);
+                                                       if (item != null)
+                                                               lt.chatMessage(String.format(formats[i], item.description));
+                                               }
+                                               return null;
+                                       } else if (objStore.isItem()) {
+                                               Item itmStore = (Item) objStore;
+                                               return "You see " + itmStore.description + ".";
+                                       } else if (objStore.isProp()) {
+                                               Prop prpStore = (Prop) objStore;
+                                               return "You see " + prpStore.description + ".";
+                                       } else if (objStore.isSign()) {
+                                               Sign sgnStore = (Sign) objStore;
+                                               return "The sign says " + sgnStore.strMessage + ".";
+                                       } else if (objStore.isPlayerMerchant()) {
+                                               lt.chatMessage("You see a merchant that sells");
+                                               PlayerMerchant pmrStore = (PlayerMerchant) objStore;
+                                               boolean blnEmptyMerchant = true;
+                                               for (LinkedList<Item> list : pmrStore.vctItems.values()) {
+                                                       Item item = (Item) list.element();
+                                                       cmdline = item.name;
+                                                       String strSpacer = "\t";
+                                                       if (cmdline.length() < 11) {
+                                                               strSpacer = "\t\t";
+                                                       }
+                                                       lt.chatMessage("\t" + cmdline + strSpacer + item.description);
+                                                       blnEmptyMerchant = false;
+                                               }
+                                               if (blnEmptyMerchant) {
+                                                       lt.chatMessage("\tNothing at the moment.");
+                                               }
+                                       } else if (objStore.isMerchant()) {
+                                               lt.chatMessage("You see a merchant that sells");
+                                               Merchant mrcStore = (Merchant) objStore;
+                                               boolean blnEmptyMerchant = true;
+                                               for (String item : mrcStore.items) {
+                                                       Item itmStore = game.getItem(item);
+                                                       if (itmStore != null) {
+                                                               String strSpacer = "\t";
+                                                               if (item.length() < 11) {
+                                                                       strSpacer = "\t\t";
+                                                               }
+                                                               lt.chatMessage("\t" + item + strSpacer + itmStore.description);
+                                                               blnEmptyMerchant = false;
+                                                       } else {
+                                                               if (item.equals("pet")) {
+                                                                       lt.chatMessage("\tpets.");
+                                                                       blnEmptyMerchant = false;
+                                                               } else {
+                                                                       item = item.substring(6, item.length());
+                                                                       lt.chatMessage("\ttraining in " + item);
+                                                                       blnEmptyMerchant = false;
+                                                               }
+                                                       }
+                                               }
+                                               if (blnEmptyMerchant) {
+                                                       lt.chatMessage("\tNothing.");
+                                               }
+                                               return null;
+                                       }
+                               }
+                               return "You don't see that here.";
+                       }
+
+                       case "inv":
+                       case "inventory": {
+                               final String[] formats = {
+                                       "Wielded: %s",
+                                       "Arms: %s",
+                                       "Legs: %s",
+                                       "Torso: %s",
+                                       "Waist: %s",
+                                       "Neck: %s",
+                                       "Skull: %s",
+                                       "Eyes: %s",
+                                       "Hands: %s"};
+                               lt.chatMessage("-Worn-");
+                               for (int i = 0; i < formats.length; i++) {
+                                       Item item = lt.wornItems.getWorn(i);
+                                       if (item != null)
+                                               lt.chatMessage(String.format(formats[i], item.description));
+                               }
+                               lt.chatMessage("-Inventory-:");
+                               for (LinkedList<Item> list : lt.itemList.values()) {
+                                       if (!list.isEmpty()) {
+                                               Item item = (Item) list.element();
+                                               lt.chatMessage(list.size() + " " + item.name);
+                                       }
+                               }
+                               return null;
+                       }
+
+                       case "help": {
+                               File file;
+                               String title;
+
+                               // FIXME: was atomic
+                               if (args == null) {
+                                       file = new File("help");
+                                       title = "Help";
+                               } else {
+                                       if (args.indexOf("..") != -1) {
+                                               return "There is no help on that subject";
+                                       }
+                                       file = new File("helpFiles/" + args);
+                                       title = "Help on " + args;
+                               }
+
+                               try (RandomAccessFile helpFile = new RandomAccessFile(file, "r")) {
+                                       lt.chatMessage(title);
+                                       while ((cmdline = helpFile.readLine()) != null) {
+                                               lt.chatMessage(cmdline);
+                                       }
+                               } catch (IOException e) {
+                                       game.log.printError("parseCommand():When " + lt.name + " tried to get help on " + args, e);
+                                       return "There is no help on that subject";
+                               }
+                               return null;
+                       }
+
+                       case "get": {
+                               if (args == null) {
+                                       return "Get what?";
+                               }
+                               DuskObject objStore = lt.getLocalObject(args);
+                               if (objStore == null) {
+                                       return "You don't see that here.";
+                               }
+                               if (!objStore.isItem()) {
+                                       return "You can't get that.";
+                               }
+                               Item itmStore = (Item) objStore;
+                               if (Math.abs(lt.x - itmStore.x) + Math.abs(lt.y - itmStore.y) < 2) {
+                                       if (lt.privs > 2) {
+                                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":gets " + args + ":" + lt.x + "," + lt.y);
+                                       }
+                                       lt.itemList.addElement(itmStore);
+                                       lt.updateItems();
+                                       game.removeDuskObject(itmStore);
+                               } else {
+                                       return "That's too far away.";
+                               }
+                               itmStore.onGetItem(game, lt);
+                               return null;
+                       }
+
+                       case "drop": {
+                               if (args == null) {
+                                       return "Drop what?";
+                               }
+                               int intDot = args.indexOf(".");
+                               int intNumToDrop = 1;
+                               if (intDot != -1) {
+                                       try {
+                                               intNumToDrop = Integer.parseInt(args.substring(0, intDot));
+                                       } catch (NumberFormatException e) {
+                                               intNumToDrop = 1;
+                                       }
+                               }
+                               Item itmStore = lt.getItem(args);
+                               if (itmStore != null) {
+                                       String strMessage = "You drop " + itmStore.name + ".";
+                                       if (intNumToDrop > 1) {
+                                               strMessage = "You drop " + intNumToDrop + " " + itmStore.name + ".";
+                                       }
+                                       if (itmStore.intCost == 0) {
+                                               strMessage = "A " + itmStore.name + " vanishes into thin air.";
+                                               if (intNumToDrop > 1) {
+                                                       strMessage = intNumToDrop + " " + itmStore.name + " vanish into thin air.";
+                                               }
+                                       }
+                                       if (lt.privs > 2) {
+                                               game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":drops " + args + ":" + lt.x + "," + lt.y);
+                                       }
+                                       for (int i = 0; i < intNumToDrop; i++) {
+                                               itmStore = lt.getItemAndRemove(itmStore.name);
+                                               itmStore.x = lt.x;
+                                               itmStore.y = lt.y;
+                                               if (itmStore.intCost != 0) {
+                                                       //game.vctItems.add(itmStore);
+                                                       game.addDuskObject(itmStore);
+                                                       lt.updateItems();
+                                               }
+                                               itmStore.onDropItem(game, lt);
+                                       }
+                                       return strMessage;
+                               }
+                               return "You don't have that.";
+                       }
+
+                       case "use": {
+                               if (args == null) {
+                                       return "Use what?";
+                               }
+                               if (lt.battle == null) {
+                                       lt.useItem(args, -1);
+                               } else {
+                                       lt.battle.addCommand(lt, "use " + args);
+                               }
+                               return null;
+                       }
+                       case "eat": {
+                               if (args == null) {
+                                       return "Eat what?";
+                               }
+                               if (lt.battle == null) {
+                                       lt.useItem(args, Item.FOOD);
+                               } else {
+                                       lt.battle.addCommand(lt, "eat " + args);
+                               }
+                               return null;
+                       }
+                       case "drink": {
+                               if (args == null) {
+                                       return "Drink what?";
+                               }
+                               if (lt.battle == null) {
+                                       lt.useItem(args, Item.DRINK);
+                               } else {
+                                       lt.battle.addCommand(lt, "drink " + args);
+                               }
+                               return null;
+                       }
+
+                       case "give": {
+                               if (args == null) {
+                                       return "Give who what?";
+                               }
+                               StringTokenizer tknStore = new StringTokenizer(args, " ");
+                               String strStore2 = null;
+                               try {
+                                       strStore2 = tknStore.nextToken();
+                               } catch (Exception e) {
+                                       return "Give who what?";
+                               }
+                               DuskObject objStore = lt.getLocalObject(strStore2);
+                               if (objStore == null) {
+                                       return "You don't see them here.";
+                               }
+                               if (!objStore.isLivingThing()) {
+                                       return "You can't give to that.";
+                               }
+                               LivingThing thnStore = (LivingThing) objStore;
+                               if ((lt.privs < 3) && (Math.abs(thnStore.x - lt.x) + Math.abs(thnStore.y - lt.y) > 1)) {
+                                       return "They're too far away.";
+                               }
+                               args = args.substring(strStore2.length() + 1);
+                               if (lt.privs > 2) {
+                                       game.log.printMessage(Log.INFO, "godcommand:" + lt.name + ":gives " + args + " to " + strStore2 + ":" + lt.x + "," + lt.y);
+                               }
+                               if (args.startsWith("gp")) {
+                                       args = args.substring(3);
+                                       try {
+                                               int intStore = Integer.parseInt(args);
+                                               if (intStore < 0) {
+                                                       return "You can't give negative money!";
+                                               }
+                                               if (intStore <= lt.cash) {
+                                                       lt.cash -= intStore;
+                                                       thnStore.cash += intStore;
+                                                       lt.updateStats();
+                                                       thnStore.updateStats();
+                                                       thnStore.chatMessage(lt.name + " gives you " + intStore + "gp.");
+                                                       return "You give " + thnStore.name + " " + intStore + "gp.";
+                                               } else {
+                                                       lt.chatMessage("You don't have that much gp");
+                                               }
+                                       } catch (Exception e) {
+                                               return "That is not a valid amount of gp to give.";
+                                       }
+                               }
+                               int intDot = args.indexOf(".");
+                               int intNumToGive = 1;
+                               if (intDot != -1) {
+                                       try {
+                                               intNumToGive = Integer.parseInt(args.substring(0, intDot));
+                                       } catch (NumberFormatException e) {
+                                               intNumToGive = 1;
+                                       }
+                               }
+                               Item itmStore = lt.getItem(args);
+                               if (itmStore != null) {
+                                       String strMessage = lt.name + " gives you ";
+                                       String strMessage2 = "You give " + thnStore.name + " ";
+                                       if (intNumToGive > 1) {
+                                               strMessage += intNumToGive + " ";
+                                               strMessage2 += intNumToGive + " ";
+                                       }
+                                       strMessage += itmStore.name + ".";
+                                       strMessage2 += itmStore.name + ".";
+                                       cmdline = itmStore.name;
+
+                                       while (intNumToGive > 0) {
+                                               itmStore = lt.getItemAndRemove(cmdline);
+                                               thnStore.itemList.addElement(itmStore);
+                                               intNumToGive--;
+
+                                               itmStore.onDropItem(game, lt);
+                                               itmStore.onGetItem(game, thnStore);
+                                       }
+
+                                       thnStore.chatMessage(strMessage);
+                                       thnStore.updateItems();
+                                       lt.updateItems();
+                                       return strMessage2;
+                               }
+                               return "You don't have that.";
+                       }
+
+                       case "buy": {
+                               if (args == null) {
+                                       return "Buy what?";
+                               }
+                               int quantity;
+                               try {
+                                       int i = args.indexOf(" ");
+                                       quantity = Integer.parseInt(args.substring(0, i));
+                                       args = args.substring(i + 1);
+                               } catch (Exception e) {
+                                       return "How many of what do you want to buy?";
+                               }
+                               if (quantity > 100) {
+                                       quantity = 100;
+                               } else if (quantity < 1) {
+                                       return "You can't buy less than one of something.";
+                               }
+                               PlayerMerchant pmrStore = game.overPlayerMerchant(lt.x, lt.y);
+                               if (pmrStore != null) {
+                                       long numItem = pmrStore.contains(args);
+                                       if (numItem > 0) {
+                                               Item itmStore = game.getItem(args);
+                                               if (itmStore != null) {
+                                                       if (quantity > numItem) {
+                                                               return "This merchant does not have that many.";
+                                                       }
+                                                       int intCost = (itmStore.intCost * 3) / 4;
+                                                       if (lt.name.equalsIgnoreCase(pmrStore.strOwner)) {
+                                                               intCost = 0;
+                                                       }
+                                                       if (intCost * quantity > lt.cash) {
+                                                               return "You can't afford that";
+                                                       } else {
+                                                               lt.cash -= intCost * quantity;
+                                                               pmrStore.cash += intCost * quantity;
+                                                               itmStore = pmrStore.remove(args);
+                                                               lt.itemList.addElement(itmStore);
+                                                               for (int i = 1; i < quantity; i++) {
+                                                                       itmStore = pmrStore.remove(args);
+                                                                       lt.itemList.addElement(itmStore);
+                                                               }
+                                                               lt.updateItems();
+                                                               lt.updateStats();
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               Merchant mrcStore = game.overMerchant(lt.x, lt.y);
+                               if (mrcStore == null) {
+                                       return "Buy from whom?";
+                               }
+                               if (lt.getFollowing() != null && lt.getFollowing().isPet()) {
+                                       if (args.startsWith(lt.getFollowing().name + ":")) {
+                                               args = args.substring(lt.getFollowing().name.length() + 1);
+                                               if (mrcStore.contains(args)) {
+                                                       if (args.startsWith("train:")) {
+                                                               args = args.substring(6);
+                                                               mrcStore.train(args, quantity, lt.getFollowing());
+                                                               lt.updateStats();
+                                                       }
+                                               }
+                                               return null;
+                                       }
+                               }
+                               if (mrcStore.contains(args)) {
+                                       if (args.startsWith("train:")) {
+                                               args = args.substring(6);
+                                               mrcStore.train(args, quantity, lt);
+                                               lt.updateStats();
+                                       } else {
+                                               if (args.startsWith("pet")) {
+                                                       mrcStore.pet(lt);
+                                                       lt.updateStats();
+                                               } else {
+                                                       Item itmStore = game.getItem(args);
+                                                       if (itmStore != null) {
+                                                               if (itmStore.intCost * quantity > lt.cash) {
+                                                                       return "You can't afford that";
+                                                               } else {
+                                                                       lt.cash -= itmStore.intCost * quantity;
+                                                                       lt.itemList.addElement(itmStore);
+                                                                       for (int i = 1; i < quantity; i++) {
+                                                                               lt.itemList.addElement(game.getItem(args));
+                                                                       }
+                                                                       lt.updateItems();
+                                                                       lt.updateStats();
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               return null;
+                       }
+
+                       case "sell": {
+                               if (args == null) {
+                                       return "Sell what?";
+                               }
+
+                               PlayerMerchant pmrStore = game.overPlayerMerchant(lt.x, lt.y);
+                               if (pmrStore != null) {
+                                       if (lt.name.equalsIgnoreCase(pmrStore.strOwner)) {
+                                               int quantity = 1;
+                                               try {
+                                                       int i = args.indexOf(" ");
+                                                       quantity = Integer.parseInt(args.substring(0, i));
+                                                       args = args.substring(i + 1);
+                                               } catch (Exception e) {
+                                                       return "How many of what do you want to sell?";
+                                               }
+                                               Item itmStore = lt.getItem(args);
+                                               for (int i = 0; i < quantity; i++) {
+                                                       itmStore = lt.getItemAndRemove(args);
+                                                       if (itmStore != null) {
+                                                               itmStore.onDropItem(game, lt);
+                                                               pmrStore.add(itmStore);
+                                                               lt.isSaveNeeded = true;
+                                                       } else {
+                                                               i = quantity;
+                                                       }
+                                               }
+                                               lt.updateItems();
+                                               lt.updateStats();
+                                               return null;
+                                       }
+                                       return "You cannot sell items to this merchant.";
+                               }
+
+                               Merchant mrcStore = game.overMerchant(lt.x, lt.y);
+                               if (mrcStore == null) {
+                                       return "Sell that to whom?";
+                               }
+                               int quantity = 1;
+                               try {
+                                       int i = args.indexOf(" ");
+                                       quantity = Integer.parseInt(args.substring(0, i));
+                                       args = args.substring(i + 1);
+                               } catch (Exception e) {
+                                       return "How many of what do you want to sell?";
+                               }
+                               if (quantity > 100) {
+                                       quantity = 100;
+                               }
+                               Item itmStore = lt.getItem(args);
+                               for (int i = 0; i < quantity; i++) {
+                                       itmStore = lt.getItemAndRemove(args);
+                                       if (itmStore != null) {
+                                               itmStore.onDropItem(game, lt);
+                                               lt.cash += (itmStore.intCost / 2);
+                                               lt.isSaveNeeded = true;
+                                       } else {
+                                               i = quantity;
+                                       }
+                               }
+                               lt.updateItems();
+                               lt.updateStats();
+                               return null;
+                       }
+
+                       case "cast": {
+                               if (args == null) {
+                                       return "Cast what?";
+                               }
+                               if (lt.battle == null) {
+                                       lt.castSpell(args);
+                               } else {
+                                       lt.battle.addCommand(lt, "cast " + args);;
+                               }
+                               return null;
+                       }
+
+                       case "follow": {
+                               if (args == null) {
+                                       return "Follow who?";
+                               }
+                               if (lt.isSleeping) {
+                                       return "You can't do that while you're sleeping";
+                               }
+                               DuskObject objStore = lt.getLocalObject(args);
+                               if (objStore == null) {
+                                       return "You don't see that here.";
+                               }
+                               if (objStore.isLivingThing()) {
+                                       LivingThing thnStore = (LivingThing) objStore;
+                                       if (lt.getMaster() != null && thnStore != lt.getMaster()) {
+                                               if (lt.isPet()) {
+                                                       return "You can only follow your owner.";
+                                               }
+                                               return "You're already following someone. Leave them first.";
+                                       }
+                                       if (Math.abs(lt.x - thnStore.x) + Math.abs(lt.y - thnStore.y) > 1) {
+                                               return "They're too far away.";
+                                       }
+                                       if (thnStore == lt) {
+                                               return "You can't follow yourself.";
+                                       }
+                                       if (!thnStore.isPlayer() && !lt.isMob()) {
+                                               return "You can only follow players.";
+                                       }
+                                       if (thnStore.noFollow || (thnStore.isPet() && thnStore.getMaster().noFollow)) {
+                                               return "They won't let you follow them.";
+                                       }
+                                       if (lt.isPet()) {
+                                               thnStore.setFollowing(lt);
+                                               lt.setMaster(thnStore);
+                                               thnStore.updateStats();
+                                               lt.updateStats();
+                                               return "You are now following " + lt.getMaster().name + ".";
+                                       }
+                                       LivingThing thnStore2 = thnStore;
+                                       while (thnStore2 != null) {
+                                               if (lt == thnStore2) {
+                                                       return "You're already in that group.";
+                                               }
+                                               thnStore2 = thnStore2.getMaster();
+                                       }
+                                       thnStore.chatMessage("You are now being followed by " + lt.name + ".");
+                                       while (thnStore.getFollowing() != null) {
+                                               thnStore = thnStore.getFollowing();
+                                               if (thnStore.isPlayer()) {
+                                                       thnStore.chatMessage("You are now being followed by " + lt.name + ".");
+                                               }
+                                       }
+                                       thnStore.setFollowing(lt);
+                                       lt.setMaster(thnStore);
+                                       thnStore.updateStats();
+                                       lt.updateStats();
+                                       return "You are now following " + lt.getMaster().name + ".";
+                               }
+                               return "That's not something you can follow.";
+                       }
+
+                       case "unfollow": {
+                               if (args == null) {
+                                       return "Unfollow who?";
+                               }
+                               LivingThing thnStore = lt.getFollowing();
+                               if (thnStore != null && thnStore.isPet()) {
+                                       if (thnStore.name.equalsIgnoreCase(args)) {
+                                               lt.halt();
+                                               lt.chatMessage("Do you really want to permanently erase your pet?");
+                                               try {
+                                                       if (lt.instream.readLine().equalsIgnoreCase("yes")) {
+                                                               lt.getFollowing().close();
+                                                               File deleteme = new File("pets/" + lt.name.toLowerCase());
+                                                               deleteme.delete();
+                                                               deleteme = new File("pets/" + lt.name.toLowerCase() + ".backup");
+                                                               deleteme.delete();
+                                                               lt.getFollowing().close();
+                                                               lt.setFollowing(lt.getFollowing().getFollowing());
+                                                               lt.proceed();
+                                                               return "Your pet has been erased.";
+                                                       }
+                                               } catch (Exception e) {
+                                                       game.log.printError("parseCommand():While unfollowing pet for " + lt.name, e);
+                                               }
+                                               lt.proceed();
+                                               return null;
+                                       }
+                                       thnStore = thnStore.getFollowing();
+                               }
+                               while (thnStore != null) {
+                                       if (thnStore.name.equalsIgnoreCase(args)) {
+                                               if (thnStore.isPet()) {
+                                                       thnStore = thnStore.getMaster();
+                                               }
+                                               thnStore.removeFromGroup();
+                                               return null;
+                                       }
+                                       thnStore = thnStore.getFollowing();
+                               }
+                               return "They're not following you.";
+                       }
+
+                       case "stay": {
+                               if (lt.isPet()) {
+                                       lt.removeFromGroup();
+                                       return Commands.parseCommand(lt, game, "emote sits down to await " + lt.getMaster().name + "'s return.");
+                               }
+                               return (Commands.parseCommand(lt, game, "emote stays like a good little puppy."));
+                       }
+
+                       case "leave": {
+                               if (lt.isPet()) {
+                                       return "You cannot leave your master unless he unfollows you.";
+                               }
+                               lt.removeFromGroup();
+                               return "You are now on your own.";
+                       }
+
+                       case "unclan": {
+                               if (lt.clan.equals("none")) {
+                                       return "You're not in a clan.";
+                               }
+                               if (lt.battle != null) {
+                                       return "Wait until you're done battling.";
+                               }
+                               try {
+                                       lt.halt();
+                                       lt.chatMessage("Are you sure you want to drop out of your clan? If so type yes.");
+                                       if (lt.instream.readLine().equalsIgnoreCase("yes")) {
+                                               lt.clan = "none";
+                                               if (lt.privs == 1) {
+                                                       lt.privs = 0;
+                                               }
+                                               lt.proceed();
+                                               game.removeDuskObject(lt);
+                                               game.addDuskObject(lt);
+                                               return "You have been removed from your clan.";
+                                       }
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While " + lt.name + " was trying to dropout of their clan", e);
+                               }
+                               lt.proceed();
+                               return null;
+                       }
+
+                       case "description": {
+                               if (args == null) {
+                                       lt.description = null;
+                                       return "Your description has been removed.";
+                               }
+                               lt.description = args;
+                               return "Your description has been set to:" + lt.description;
+                       }
+
+                       case "title": {
+                               if (!lt.isPlayer()) {
+                                       return "Only players may have titles.";
+                               }
+                               if (args == null) {
+                                       lt.title = null;
+                                       return "Your title has been removed.";
+                               }
+                               lt.title = args;
+                               if (lt.title.length() > game.titlecap) {
+                                       lt.title = lt.title.substring(0, game.titlecap);
+                               }
+                               return "Your title has been set to:" + lt.title;
+                       }
+
+                       case "password": {
+                               if (!lt.isPlayer()) {
+                                       return "Only players can change their password.";
+                               }
+                               try {
+                                       lt.halt();
+                                       lt.chatMessage("Enter your current password.");
+                                       String strOldPass = lt.instream.readLine();
+                                       if (!strOldPass.equals(lt.password)) {
+                                               lt.proceed();
+                                               return "Sorry, that is not your password.";
+                                       }
+                                       lt.chatMessage("Enter a new password.");
+                                       String strNewPass = lt.instream.readLine();
+                                       lt.chatMessage("Repeat that password.");
+                                       String strNewPassRepeat = lt.instream.readLine();
+                                       if (strNewPass == null) {
+                                               lt.proceed();
+                                               return "Not a valid password.";
+                                       }
+                                       if (!strNewPass.equals(strNewPassRepeat)) {
+                                               lt.proceed();
+                                               return "Sorry, those passwords do not match.";
+                                       }
+                                       lt.password = strNewPass;
+                                       lt.proceed();
+                                       return "Your password has now been changed.";
+                               } catch (Exception e) {
+                                       game.log.printError("parseCommand():While " + lt.name + " was changing their password", e);
+                               }
+                               lt.proceed();
+                       }
+
+                       case "wear": {
+                               if (args == null) {
+                                       return "Wear what?";
+                               }
+                               // FIXME: this should go on livingthing, but the interaction flow is messy
+                               LinkedList<Item> qStore = lt.itemList.get(args);
+                               if (qStore != null) {
+                                       Item itmStore = (Item) qStore.element();
+                                       int where = -1;
+
+                                       switch (itmStore.intType) {
+                                               case (1): {
+                                                       where = Equipment.WIELD;
+                                                       break;
+                                               }
+                                               case (2):
+                                                       where = itmStore.intKind + Equipment.ARMS;
+                                                       break;
+                                               default:
+                                                       return "You can't wear that";
+                                       }
+
+                                       Item old = lt.wornItems.wear(where, itmStore);
+                                       if (old != null) {
+                                               lt.itemList.addElement(old);
+                                               lt.onUnwear(old);
+                                       }
+                                       lt.onWear(itmStore);
+
+                                       lt.itemList.removeElement(itmStore.name);
+                                       if (lt.isPet()) {
+                                               lt.getMaster().updateStats();
+                                       }
+                                       if (lt.isPlayer()) {
+                                               lt.updateStats();
+                                       }
+                                       lt.updateEquipment();
+                                       lt.updateItems();
+                                       return null;
+                               }
+                               return "You don't have that";
+                       }
+                       case "unwear": {
+                               if (args == null) {
+                                       return "Unwear what?";
+                               }
+                               lt.unWear(args);
+                               return null;
+                       }
+                       case "rement": {
+                               if (args == null) {
+                                       return null;
+                               }
+                               long lngID = Long.parseLong(args);
+                               lt.removeEntity(lngID);
+                               return null;
+                       }
+                       case "audio": {
+                               if (args == null) {
+                                       if (lt.audioon) {
+                                               return "Your audio is turned on.";
+                                       }
+                                       return "Your audio is turned off.";
+                               } else if (args.equalsIgnoreCase("off")) {
+                                       lt.audioon = false;
+                                       return "Your audio has been turned off.";
+                               } else if (args.equalsIgnoreCase("on")) {
+                                       lt.audioon = true;
+                                       return "Your audio has been turned on.";
+                               }
+                       }
+                       case "color": {
+                               if (args == null) {
+                                       if (lt.coloron) {
+                                               return "Your color is turned on.";
+                                       }
+                                       return "Your color is turned off.";
+                               } else if (args.equalsIgnoreCase("off")) {
+                                       lt.coloron = false;
+                                       return "Your color has been turned off.";
+                               } else if (args.equalsIgnoreCase("on")) {
+                                       lt.coloron = true;
+                                       return "Your color has been turned on.";
+                               }
+                       }
+                       case "highlight": {
+                               if (args == null) {
+                                       if (lt.highlight) {
+                                               return "Highlighting of enemies in battle is turned on.";
+                                       }
+                                       return "Highlighting of enemies in battle is turned off.";
+                               } else if (args.equalsIgnoreCase("off")) {
+                                       lt.highlight = false;
+                                       lt.clearFlags();
+                                       return "Highlighting of enemies in battle has been turned off.";
+                               } else if (args.equalsIgnoreCase("on")) {
+                                       lt.highlight = true;
+                                       return "Highlighting of enemies in battle has been turned on.";
+                               }
+                       }
+                       case "popup": {
+                               // FIXME: TBD
+                               if (args == null) {
+                                       if (lt.popup) {
+                                               return "You have popup windows turned on.";
+                                       }
+                                       return "You have popup windows turned off.";
+                               } else if (args.equalsIgnoreCase("off")) {
+                                       lt.popup = false;
+                                       return "You have turned popup windows off.";
+                               } else if (args.equalsIgnoreCase("on")) {
+                                       lt.popup = true;
+                                       return "You have turned popup windows on.";
+                               }
+                       }
+                       case "nofollow": {
+                               if (args == null) {
+                                       if (lt.noFollow) {
+                                               return "You are not allowed to be followed.";
+                                       }
+                                       return "You can be followed.";
+                               } else if (args.equalsIgnoreCase("off")) {
+                                       lt.noFollow = false;
+                                       return "You can now be followed.";
+                               } else if (args.equalsIgnoreCase("on")) {
+                                       lt.noFollow = true;
+                                       return "You can no longer be followed.";
+                               }
+                       }
+                       case "ignore": {
+                               if (args == null) {
+                                       return "Ignore who?";
+                               }
+                               LivingThing thnStore = game.getPlayer(args);
+                               if (thnStore == null) {
+                                       return "They're not in this world.";
+                               }
+                               String strIgnoreName = thnStore.name.toLowerCase();
+                               if (lt.name.equalsIgnoreCase(strIgnoreName)) {
+                                       return "Trying to ignore yourself is not a good sign.";
+                               }
+                               if (thnStore.privs > 2) {
+                                       return "You cannot ignore a god.";
+                               }
+                               if (!lt.ignoreList.contains(strIgnoreName)) {
+                                       lt.ignoreList.add(strIgnoreName);
+                               } else {
+                                       return "You are already ignoring them.";
+                               }
+                               return "You are now ignoring " + strIgnoreName;
+                       }
+                       case "unignore": {
+                               if (args == null) {
+                                       return "UnIgnore who?";
+                               }
+                               String strIgnoreName = args.toLowerCase();
+                               if (strIgnoreName == "all") {
+                                       lt.ignoreList.clear();
+                                       return "You are no longer ignoring anyone.";
+                               }
+                               if (lt.ignoreList.contains(strIgnoreName)) {
+                                       lt.ignoreList.remove(strIgnoreName);
+                               } else {
+                                       return "You are not ignoring them.";
+                               }
+                               return "You are no longer ignoring " + strIgnoreName;
+                       }
+                       case "appletimages": {
+                               lt.updateAppletImages();
+                               return null;
+                       }
+                       case "applicationimages": {
+                               lt.updateApplicationImages();
+                               return null;
+                       }
+                       case "notdead": {
+                               return null;
+                       }
+                       case "quit":
+                       case "logout": {
+                               if (lt.battle == null) {
+                                       lt.close();
+                                       return null;
+                               }
+                               return "You cannot quit in the middle of a fight.";
+                       }
+               }
+               if (!blnFoundScriptedCommand) {
+                       return "huh?";
+               }
+               return null;
+       }
+}
diff --git a/DuskServer/src/duskz/server/Condition.java b/DuskServer/src/duskz/server/Condition.java
new file mode 100644 (file)
index 0000000..76071e8
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, clean up script commands.
+ */
+package duskz.server;
+
+import duskz.server.entity.LivingThing;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/**
+ * Condition describes a temporary or permanent effect.
+ *
+ * @author Tom Weingarten
+ */
+public class Condition {
+
+       public final String name;
+       public int duration = -1, //number of occurances till end. -1 = infinity
+                       occurance = 1, //number of ticks per occurance
+                       ticksPast = 0; //how many ticks since last occurance
+       public boolean display = true; //should the player be able to see the condition
+       // Script names
+       private String onStartScript = null,
+                       onOccuranceScript = null,
+                       onEndScript = null;
+
+       public Condition(String name) {
+               this.name = name;
+       }
+
+       public static Condition getCondition(String name) throws IOException {
+               String s;
+               Condition store = new Condition(name);
+
+               try (RandomAccessFile rafConditionDef = new RandomAccessFile("defConditions/" + name.toLowerCase(), "r")) {
+                       s = rafConditionDef.readLine();
+                       while (!(s == null || s.equals("."))) {
+                               switch (s.toLowerCase()) {
+                                       case "duration":
+                                               store.duration = Integer.parseInt(rafConditionDef.readLine());
+                                               break;
+                                       case "occurance":
+                                               store.occurance = Integer.parseInt(rafConditionDef.readLine());
+                                               break;
+                                       case "onstart":
+                                               store.onStartScript = rafConditionDef.readLine();
+                                               break;
+                                       case "onoccurance":
+                                               store.onOccuranceScript = rafConditionDef.readLine();
+                                               break;
+                                       case "onend":
+                                               store.onEndScript = rafConditionDef.readLine();
+                                               break;
+                                       case "nodisplay":
+                                               store.display = false;
+                                               break;
+                               }
+                               s = rafConditionDef.readLine();
+                       }
+               }
+               return store;
+       }
+
+       void runScript(DuskEngine engGame, LivingThing trigger, String script) {
+               if (script != null) {
+                       try {
+                               Script scrStore = new Script("scripts/" + script, engGame, false);
+                               scrStore.varVariables.addVariable("trigger", trigger);
+                               scrStore.varVariables.addVariable("condition", name);
+                               scrStore.runScript();
+                               scrStore.close();
+                       } catch (Exception e) {
+                               engGame.log.printError("Condition.onStart() for condition \"" + name + "\"", e);
+                       }
+               }
+       }
+
+       public void onStart(DuskEngine engGame, LivingThing trigger) {
+               runScript(engGame, trigger, onStartScript);
+       }
+
+       public void onOccurance(DuskEngine engGame, LivingThing trigger) {
+               runScript(engGame, trigger, onOccuranceScript);
+       }
+
+       public void onEnd(DuskEngine engGame, LivingThing trigger) {
+               runScript(engGame, trigger, onEndScript);
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/Config.java b/DuskServer/src/duskz/server/Config.java
new file mode 100644 (file)
index 0000000..75decba
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+import java.util.Properties;
+import java.io.FileInputStream;
+
+class Config extends Properties {
+
+       DuskEngine engGame;
+
+       public Config(DuskEngine inGame, String strFileName) {
+               engGame = inGame;
+               try {
+                       load(new FileInputStream(strFileName));
+               } catch (Exception e) {
+                       engGame.log.printError("Config::Config(String) - Error loading preferences.", e);
+               }
+       }
+
+       public String getString(String strKey, String strDefault) {
+               String strReturn = getProperty(strKey, strDefault);
+               engGame.log.printMessage(Log.VERBOSE, strKey + " = " + strReturn);
+               return strReturn;
+       }
+
+       public int getInt(String strKey, int intDefault) {
+               int intReturn = Integer.parseInt(getProperty(strKey, String.valueOf(intDefault)));
+               engGame.log.printMessage(Log.VERBOSE, strKey + " = " + intReturn);
+               return intReturn;
+       }
+
+       public boolean getBoolean(String strKey, boolean blnDefault) {
+               boolean blnReturn = (Boolean.valueOf(getProperty(strKey, String.valueOf(blnDefault))).booleanValue());
+               engGame.log.printMessage(Log.VERBOSE, strKey + " = " + blnReturn);
+               return blnReturn;
+       }
+
+       public long getLong(String strKey, long lngDefault) {
+               long lngReturn = Long.parseLong(getProperty(strKey, String.valueOf(lngDefault)));
+               engGame.log.printMessage(Log.VERBOSE, strKey + " = " + lngReturn);
+               return lngReturn;
+       }
+
+       public double getDouble(String strKey, double dblDefault) {
+               double dblReturn = Double.parseDouble(getProperty(strKey, String.valueOf(dblDefault)));
+               engGame.log.printMessage(Log.VERBOSE, strKey + " = " + dblReturn);
+               return dblReturn;
+       }
+}
diff --git a/DuskServer/src/duskz/server/Constants.java b/DuskServer/src/duskz/server/Constants.java
new file mode 100644 (file)
index 0000000..0d4e9d8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+/**
+ * This class defines all constants used throughout the code system.
+ *
+ * @Author Lee Templeton (Lone Wolf)
+ */
+//TODO: Move all commonly used variables to here
+public interface Constants {
+       // DUSKENGINE Section
+
+       static final int MIN = 0;
+       static final int MAX = 1;
+       // DUSKOBJECT Section
+       static final int NUMBER = 0;
+       static final int STRING = 1;
+       static final int LIVING_THING = 2;
+       static final int ITEM = 3;
+       // ATTRIBUTE Section
+       static final int MAIN = 0;
+       static final int SECONDARY = 1;
+       static final int BONUS = 2;
+       static final int ALL = 100;
+       // ITEM Section
+       static final int ORDINARY_ITEM = 0;
+       static final int WEAPON = 1;
+       static final int ARMOR = 2;
+       static final int FOOD = 3;
+       static final int DRINK = 4;
+       static final int RANGED = 5;
+       static final int CONTAINER = 6;
+       // CAP Section
+       static final int STAT_CAP = 100;
+       static final int SKILL_CAP = 100;
+       static final int MAX_CAP = 200;
+       // Strings
+       static final String CONFIG_FILE_NAME = "prefs";
+       static final String CONFIG_FILE_DIR = "conf/";
+}
diff --git a/DuskServer/src/duskz/server/DuskEngine.java b/DuskServer/src/duskz/server/DuskEngine.java
new file mode 100644 (file)
index 0000000..cd438ef
--- /dev/null
@@ -0,0 +1,2045 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - general cleanup, modernisation, refactoring,
+ * abstracting, fixing synchronisation issues.
+ */
+package duskz.server;
+
+import duskz.protocol.MessageType;
+import duskz.server.entity.TileMap;
+import duskz.server.entity.Mob;
+import duskz.server.entity.Merchant;
+import duskz.server.entity.Sign;
+import duskz.server.entity.Item;
+import duskz.server.entity.Prop;
+import duskz.server.entity.DuskObject;
+import duskz.server.entity.PlayerMerchant;
+import duskz.server.entity.LivingThing;
+import duskz.protocol.ServerMessage;
+import duskz.protocol.TransactionItem;
+import java.io.*;
+import java.io.PrintStream;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.StringTokenizer;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Properties;
+
+/**
+ * DuskEngine is the center of the Dusk game.
+ *
+ * @author Tom Weingarten
+ */
+public class DuskEngine implements Runnable {
+       //Logger
+
+       public Log log;
+       //Prefs:
+       public int port = 7400,
+                       trackerport = 7401,
+                       maxconnections = 0,
+                       petcost = 100,
+                       merchantimage,
+                       signimage,
+                       battlesound = -1,
+                       mobrespawnspeed,
+                       viewrange = 5,
+                       oldviewrange = 0,
+                       mapsize = 11,
+                       titlecap = 0,
+                       noChannelMax = 600, // defalut 600=10 minutes
+                       namecap = 20, //default 20
+                       messagecap = 120, //default 120
+                       changeRaceCpLimit = 100, //default 100cp
+                       logLevel = Log.ERROR,
+                       traincost = 100,
+                       expgainmod = 10;
+       double gplosemod = 1D / 16D, //default 1/16
+                       explosemod = 1D / 16D,
+                       gpfleemod = 1D / 64D, //default 1/64
+                       expfleemod = 1D / 64D;
+       public long lngMobTicks = 1000, //default 1000 milliseconds(1 second) per tick
+                       lngPlayerTicks = 250, //default 250 milliseconds(1/4 second) per tick
+                       floodLimit = 1000;      //default 1000 milliseconds(1 second) btw messages
+       public String trackername = "Just Some World.",
+                       site = "none",
+                       strRCAddress,
+                       strRCName,
+                       strLogFile = null,
+                       strMusicAddress;
+       public boolean blnMusic = false,
+                       blnLineOfSight = false,
+                       blnAI = false,
+                       blnIPF = false,
+                       tracker = true,
+                       blnSavingGame = false,
+                       blnShuttingDown = false;
+       // FIXME: Not public
+       public Script scrCanSeeLivingThing = null,
+                       scrCanMoveThroughLivingThing = null,
+                       scrCanAttack = null,
+                       scrOnStart = null,
+                       scrOnDeath = null,
+                       scrOnLogOut = null;
+       //End Prefs
+       public final static String version = "2.6.2.W42";
+       public final Date datStart = new Date(System.currentTimeMillis());
+       //public int MapRows,
+       //              MapColumns;
+       //public short shrMap[][];
+       //protected short shrMapOwnerPrivs[][];
+       //protected int intMapOwnerID[][];
+       //protected Config IDtoName;
+       public TileMap map;
+       final public List<Battle> battleList = new ArrayList<>();
+       // Indices of various Entities
+       final public HashSet<Merchant> merchantList = new HashSet<>();
+       /**
+        * List of mobs in game.
+        * access must be synchronised.
+        */
+       final public List<Mob> mobList = new ArrayList<>();
+       // TODO: although this is maintained, nobody access it
+       final public List<Item> itemList = new ArrayList<>();
+       final public List<Sign> signList = new ArrayList<>();
+       final public List<Prop> propList = new ArrayList<>();
+       final public List<LivingThing> petList = new ArrayList<>();
+       // tile actions, keyed by tile id
+       final public HashMap<Integer, Script> tileCanSee = new HashMap<>();
+       final public HashMap<Integer, Script> tileCanMove = new HashMap<>();
+       final public HashMap<Integer, Script> tileAction = new HashMap<>();
+       //
+       final public HashMap<String, Faction> factionMap = new HashMap<>();
+       final public HashMap<String, SpellGroup> spellGroupList = new HashMap<>();
+       /**
+        * Automatic temporary bans
+        */
+       final private HashMap<String, Long> bannedIPMap = new HashMap<>();
+       final public HashSet<LivingThing> checkConditionList = new HashSet<>();
+       public final HashMap<String, LivingThing> playersByName = new HashMap<>();
+       VariableSet varVariables;
+       public VariableSet varIP;
+       private long nextid = 0;
+       boolean blnVariableListChanged = false,
+                       blnMapHasChanged = false,
+                       blnMobListChanged = false,
+                       blnSignListChanged = false,
+                       blnMerchantListChanged = false,
+                       blnPropListChanged = false;
+
+       public DuskEngine() {
+               RandomAccessFile rafFile = null;
+               varVariables = new VariableSet();
+               varIP = new VariableSet();
+               log = new Log(System.out);
+
+               try {
+                       int x = 0,
+                                       y = 0;
+                       String strStore;
+
+                       loadPrefs();
+
+                       // Load Map
+                       File newmap = new File("shortmapx");
+                       if (newmap.exists()) {
+                               log.printMessage(Log.INFO, "Loading Map...");
+                               map = TileMap.loadMapX(newmap);
+                               log.printMessage(Log.VERBOSE, map.getCols() + "/" + map.getRows());
+                       } else {
+                               newmap = new File("shortmap");
+                               if (newmap.exists()) {
+                                       log.printMessage(Log.INFO, "Loading Map...");
+                                       map = TileMap.loadMap(newmap, TileMap.FORMAT_SHORT);
+                                       log.printMessage(Log.VERBOSE, map.getCols() + "/" + map.getRows());
+                               } else {
+                                       log.printMessage(Log.INFO, "Converting old map to new short format...");
+                                       map = TileMap.loadMap(newmap, TileMap.FORMAT_BYTE);
+                                       log.printMessage(Log.VERBOSE, map.getCols() + "/" + map.getRows());
+                               }
+                       }
+
+                       log.printMessage(Log.INFO, "Map Loaded...");
+
+                       // Loading Map tile priviledges
+                       /*
+                        File mapprivs = new File("shortmap.privs");
+                        if (mapprivs.exists()) {
+                        rafFile = new RandomAccessFile("shortmap.privs", "r");
+                        log.printMessage(Log.INFO, "Loading Map Tile Privs...");
+                        int PrivsColumns = rafFile.readInt();
+                        int PrivsRows = rafFile.readInt();
+                        if (PrivsColumns != MapColumns || PrivsRows != MapRows) {
+                        log.printMessage(Log.ERROR, "Map privs array size (" + PrivsColumns + "/" + PrivsRows + ") does not match map size (" + MapColumns + "/" + MapRows + ")");
+                        }
+                        log.printMessage(Log.ALWAYS, PrivsColumns + "/" + PrivsRows);
+                        shrMapOwnerPrivs = new short[PrivsColumns][PrivsRows];
+                        for (x = 0; x < PrivsColumns; x++) {
+                        for (y = 0; y < PrivsRows; y++) {
+                        shrMapOwnerPrivs[x][y] = rafFile.readShort();
+                        }
+                        }
+                        rafFile.close();
+                        }
+
+                        // Loading Map tile ownership
+                        File mapowners = new File("shortmap.owner");
+                        File ownerlist = new File("tile_owner_list");
+                        if (mapowners.exists() && ownerlist.exists()) {
+                        IDtoName = new Config(this, "tile_owner_list");
+                        rafFile = new RandomAccessFile("shortmap.owner", "r");
+                        log.printMessage(Log.INFO, "Loading Map Tile Ownership...");
+                        int OwnColumns = rafFile.readInt();
+                        int OwnRows = rafFile.readInt();
+                        if (OwnColumns != MapColumns || OwnRows != MapRows) {
+                        log.printMessage(Log.ERROR, "Map ownership array size (" + OwnColumns + "/" + OwnRows + ") does not match map size (" + MapColumns + "/" + MapRows + ")");
+                        }
+                        log.printMessage(Log.ALWAYS, OwnColumns + "/" + OwnRows);
+                        intMapOwnerID = new int[OwnColumns][OwnRows];
+                        for (x = 0; x < OwnColumns; x++) {
+                        for (y = 0; y < OwnRows; y++) {
+                        intMapOwnerID[x][y] = rafFile.readInt();
+                        }
+                        }
+                        rafFile.close();
+                        }*/
+
+                       // Load Merchants
+                       try {
+                               rafFile = new RandomAccessFile("merchants", "r");
+                               Merchant mrcStore;
+                               log.printMessage(Log.INFO, "Loading Merchants...");
+                               strStore = rafFile.readLine();
+                               while (!(strStore == null || strStore.equals(""))) {
+                                       mrcStore = new Merchant(this);
+                                       mrcStore.x = Integer.parseInt(strStore);
+                                       mrcStore.y = Integer.parseInt(rafFile.readLine());
+                                       log.printMessage(Log.VERBOSE, "Merchant(" + mrcStore.x + "," + mrcStore.y + ")");
+                                       strStore = rafFile.readLine();
+                                       while (strStore != null && !strStore.equals("") && !strStore.equalsIgnoreCase("end")) {
+                                               log.printMessage(Log.DEBUG, "\t" + strStore);
+                                               mrcStore.items.add(strStore);
+                                               strStore = rafFile.readLine();
+                                       }
+                                       if (!map.inside(mrcStore.x, mrcStore.y)) {
+                                               log.printMessage(Log.VERBOSE, "Previous merchant is off of the map, ignoring");
+                                               blnMerchantListChanged = true;
+                                       } else {
+                                               //vctMerchants.add(mrcStore);
+                                               addDuskObject(mrcStore);
+                                       }
+                                       strStore = rafFile.readLine();
+                               }
+                       } catch (Exception e) {
+                               log.printError("DuskEngine():While loading merchants", e);
+                       }
+                       rafFile.close();
+
+                       // Load Mobs
+                       LivingThing thnStore;
+                       rafFile = new RandomAccessFile("mobs", "r");
+                       log.printMessage(Log.INFO, "Loading Mobs...");
+                       strStore = rafFile.readLine();
+                       while (strStore != null) {
+                               if (strStore.equals("")) {
+                                       break;
+                               }
+                               if (strStore.equals("mob2.3")) {
+                                       strStore = rafFile.readLine();
+                                       log.printMessage(Log.VERBOSE, strStore);
+                                       try {
+                                               thnStore = new Mob(strStore,
+                                                               Integer.parseInt(rafFile.readLine()),
+                                                               Integer.parseInt(rafFile.readLine()),
+                                                               this);
+                                               if (!map.inside(thnStore.x, thnStore.y)) {
+                                                       log.printMessage(Log.VERBOSE, "Previous mob is off of the map, ignoring");
+                                                       blnMobListChanged = true;
+                                               } else {
+                                                       //vctMobs.addElement(thnStore);
+                                                       addDuskObject(thnStore);
+                                               }
+                                       } catch (Exception e) {
+                                               log.printError("DuskEngine():While loading mobs", e);
+                                       }
+                               } else {
+                                       log.printMessage(Log.VERBOSE, strStore);
+                                       try {
+                                               thnStore = new Mob(strStore,
+                                                               Integer.parseInt(rafFile.readLine()),
+                                                               Integer.parseInt(rafFile.readLine()),
+                                                               Integer.parseInt(rafFile.readLine()),
+                                                               this);
+                                               if (!map.inside(thnStore.x, thnStore.y)) {
+                                                       log.printMessage(Log.VERBOSE, "Previous mob is off of the map, ignoring");
+                                                       blnMobListChanged = true;
+                                               } else {
+                                                       //vctMobs.addElement(thnStore);
+                                                       addDuskObject(thnStore);
+                                               }
+                                       } catch (Exception e) {
+                                               log.printError("DuskEngine():While loading mobs", e);
+                                       }
+                               }
+                               strStore = rafFile.readLine();
+                       }
+                       rafFile.close();
+
+                       // Load signs
+                       Sign sgnStore;
+                       rafFile = new RandomAccessFile("signs", "r");
+                       log.printMessage(Log.INFO, "Loading Signs...");
+                       strStore = rafFile.readLine();
+                       while (!(strStore == null || strStore.equals(""))) {
+                               log.printMessage(Log.VERBOSE, strStore);
+                               sgnStore = new Sign(this, "sign", strStore, Integer.parseInt(rafFile.readLine()), Integer.parseInt(rafFile.readLine()), getID());
+                               if (!map.inside(sgnStore.x, sgnStore.y)) {
+                                       log.printMessage(Log.VERBOSE, "Previous sign is off of the map, ignoring");
+                                       blnSignListChanged = true;
+                               } else {
+                                       //vctSigns.add(sgnStore);
+                                       addDuskObject(sgnStore);
+                               }
+                               strStore = rafFile.readLine();
+                       }
+                       rafFile.close();
+
+                       // Load props
+                       Prop prpStore;
+                       rafFile = new RandomAccessFile("props", "r");
+                       log.printMessage(Log.INFO, "Loading Props...");
+                       strStore = rafFile.readLine();
+                       while (!(strStore == null || strStore.equals(""))) {
+                               log.printMessage(Log.VERBOSE, strStore);
+                               prpStore = getProp(strStore);
+                               if (prpStore != null) {
+                                       prpStore.x = Integer.parseInt(rafFile.readLine());
+                                       prpStore.y = Integer.parseInt(rafFile.readLine());
+                                       if (!map.inside(prpStore.x, prpStore.y)) {
+                                               log.printMessage(Log.VERBOSE, "Previous prop is off of the map, ignoring");
+                                               blnPropListChanged = true;
+                                       } else {
+                                               //vctProps.addElement(prpStore);
+                                               addDuskObject(prpStore);
+                                       }
+                               }
+                               strStore = rafFile.readLine();
+                       }
+                       rafFile.close();
+
+                       // Load global variables
+                       String strVarName;
+                       int intType;
+                       String strObject;
+                       double dblObject;
+                       rafFile = new RandomAccessFile("globals", "r");
+                       log.printMessage(Log.INFO, "Loading Global Variables...");
+                       strVarName = rafFile.readLine();
+                       while (!(strVarName == null || strVarName.equals(""))) {
+                               intType = Integer.parseInt(rafFile.readLine());
+                               switch (intType) {
+                                       case 0: {
+                                               dblObject = (double) Double.parseDouble(rafFile.readLine());
+                                               varVariables.addVariable(strVarName, dblObject);
+                                               log.printMessage(Log.VERBOSE, strVarName + " = " + dblObject);
+                                               break;
+                                       }
+                                       case 1: {
+                                               strObject = rafFile.readLine();
+                                               varVariables.addVariable(strVarName, strObject);
+                                               log.printMessage(Log.VERBOSE, strVarName + " = '" + strObject + "'");
+                                               break;
+                                       }
+                               }
+                               strVarName = rafFile.readLine();
+                       }
+                       rafFile.close();
+
+                       //Start onBoot script
+                       try {
+                               Script scrOnBoot = new Script("conf/onBoot", this, true);
+                               scrOnBoot.runScript();
+                               scrOnBoot.close();
+                               log.printMessage(Log.INFO, "Ran onBoot script.");
+                       } catch (Exception e) {
+                               log.printError("DuskEngine():Failed to run onBoot script, maybe it doesn't exist? (Not a fatal error)", e);
+                               log.printMessage(Log.ALWAYS, "To create an onBoot script, type \"view conf onBoot\" in game as a high or master god.");
+                       }
+               } catch (Exception e) {
+                       log.printError("DuskEngine()", e);
+               }
+       }
+
+       public boolean isGoodIP(String strIP) {
+               RandomAccessFile rafFile = null;
+               try {
+                       // Why isn't this cached?
+                       String strBlockedIP;
+                       String key = strIP.toLowerCase();
+                       rafFile = new RandomAccessFile("conf/blockedIP", "r");
+                       strBlockedIP = rafFile.readLine();
+                       while (strBlockedIP != null) {
+                               if (key.indexOf(strBlockedIP) != -1) {
+                                       rafFile.close();
+                                       return false;
+                               }
+                               strBlockedIP = rafFile.readLine();
+                       }
+                       rafFile.close();
+
+                       return !isBanned(key);
+               } catch (Exception e) {
+                       log.printError("isGoodIP():Checking for bad IP address", e);
+                       return false;
+               }
+       }
+
+       public boolean isGoodName(String strName) {
+               if (strName == null) {
+                       return false;
+               }
+               if (strName.equals("")
+                               || strName.length() > namecap
+                               || strName.toLowerCase().equals("god")
+                               || strName.toLowerCase().equals("default")) {
+                       return false;
+               }
+
+               String strValid = "0123456789][_'#";
+               char[] letters = strName.toCharArray();
+               char[] validChars = strValid.toCharArray();
+               boolean blnValid = true;
+
+               for (int n = 0; n < letters.length; n++) {
+                       if (!Character.isLetter(letters[n])) {
+                               blnValid = false;
+                               for (int i = 0; i < validChars.length; i++) {
+                                       if (letters[n] == validChars[i]) {
+                                               blnValid = true;
+                                       }
+                               }
+                       }
+               }
+               if (!blnValid) {
+                       return false;
+               }
+
+               RandomAccessFile rafFile = null;
+               try {
+                       String strDirtyWord;
+                       String strLowerCaseName = strName.toLowerCase();
+                       rafFile = new RandomAccessFile("conf/dirtyWordFile", "r");
+                       strDirtyWord = rafFile.readLine();
+                       while (strDirtyWord != null) {
+                               if (strLowerCaseName.indexOf(strDirtyWord) != -1) {
+                                       rafFile.close();
+                                       return false;
+                               }
+                               strDirtyWord = rafFile.readLine();
+                       }
+                       rafFile.close();
+               } catch (Exception e) {
+                       log.printError("isGoodName():" + strName + " had an error checking for bad name", e);
+                       return false;
+               }
+               return true;
+       }
+
+       synchronized void loadPrefs() {
+               Config settings = new Config(this, "conf/prefs");
+               //Load Prefs
+               strLogFile = settings.getString("LogFileName", strLogFile);
+               if (strLogFile != null) {
+                       try {
+                               log = new Log(new PrintStream(new FileOutputStream(strLogFile, true), true));
+                       } catch (Exception e) {
+                               log = new Log(System.out);
+                               log.printError("loadPrefs():Opening log file \"" + strLogFile + "\"", e);
+                       }
+               } else {
+                       log = new Log(System.out);
+               }
+               log.printMessage(Log.INFO, "Loading Preferences...");
+
+               logLevel = settings.getInt("LoggingLevel", logLevel);
+               log.setLogLevel(logLevel);
+
+               port = settings.getInt("Port", port);
+               tracker = settings.getBoolean("Tracker", tracker);
+               trackerport = settings.getInt("TrackerPort", trackerport);
+               trackername = settings.getString("TrackerName", trackername);
+               site = settings.getString("TrackerSite", site);
+               strRCAddress = settings.getString("RCAddress", strRCAddress);
+               strRCName = settings.getString("RCName", strRCName);
+               maxconnections = settings.getInt("MaxConnections", maxconnections);
+               blnMusic = settings.getBoolean("Music", blnMusic);
+               blnAI = settings.getBoolean("Ai", blnAI);
+               blnLineOfSight = settings.getBoolean("LineOfSight", blnLineOfSight);
+               blnIPF = settings.getBoolean("UniqueIPFilter", blnIPF);
+               changeRaceCpLimit = settings.getInt("ChangeRaceCPLimit", changeRaceCpLimit);
+               petcost = settings.getInt("PetCost", petcost);
+               messagecap = settings.getInt("MessageCap", messagecap);
+               namecap = settings.getInt("NameCap", namecap);
+               titlecap = settings.getInt("TitleCap", titlecap);
+               noChannelMax = settings.getInt("NoChannelMax", noChannelMax);
+               merchantimage = settings.getInt("MerchantImage", merchantimage);
+               signimage = settings.getInt("SignImage", signimage);
+               battlesound = settings.getInt("BattleSound", battlesound);
+               mobrespawnspeed = -1 * settings.getInt("MobReSpawnSpeed", mobrespawnspeed);
+               traincost = settings.getInt("TrainCost", traincost);
+               expgainmod = settings.getInt("ExpGainMod", expgainmod);
+               gplosemod = settings.getDouble("GpLoseMod", gplosemod);
+               explosemod = settings.getDouble("ExpLoseMod", explosemod);
+               gpfleemod = settings.getDouble("GpFleeMod", gpfleemod);
+               expfleemod = settings.getDouble("ExpFleeMod", expfleemod);
+               viewrange = settings.getInt("ViewRange", viewrange);
+               lngMobTicks = settings.getLong("MobTicks", lngMobTicks);
+               lngPlayerTicks = settings.getLong("PlayerTicks", lngPlayerTicks);
+               if (viewrange != oldviewrange) {
+                       oldviewrange = viewrange;
+                       mapsize = 1 + (2 * viewrange);
+                       for (LivingThing thnStore : playersByName.values()) {
+                               thnStore.resizeMap();
+                       }
+               }
+               //Load Triggered Scripts
+
+               // FIXME: all this 'synchronized' stuff is busted to shit, you can't lock on something
+               // that might be null or will be replaced by a new object.
+
+               try {
+                       if (scrCanSeeLivingThing != null) {
+                               synchronized (scrCanSeeLivingThing) {
+                                       scrCanSeeLivingThing.close();
+                                       scrCanSeeLivingThing = new Script("conf/canSeeLivingThing", this, true);
+                               }
+                       } else {
+                               scrCanSeeLivingThing = new Script("conf/canSeeLivingThing", this, true);
+                       }
+               } catch (Exception e) {
+                       scrCanSeeLivingThing = null;
+               }
+               try {
+                       if (scrCanMoveThroughLivingThing != null) {
+                               synchronized (scrCanMoveThroughLivingThing) {
+                                       scrCanMoveThroughLivingThing.close();
+                                       scrCanMoveThroughLivingThing = new Script("conf/canMoveThroughLivingThing", this, true);
+                               }
+                       } else {
+                               scrCanMoveThroughLivingThing = new Script("conf/canMoveThroughLivingThing", this, true);
+                       }
+               } catch (Exception e) {
+                       scrCanMoveThroughLivingThing = null;
+               }
+               try {
+                       if (scrCanAttack != null) {
+                               synchronized (scrCanAttack) {
+                                       scrCanAttack.close();
+                                       scrCanAttack = new Script("conf/canAttack", this, true);
+                               }
+                       } else {
+                               scrCanAttack = new Script("conf/canAttack", this, true);
+                       }
+               } catch (Exception e) {
+                       scrCanAttack = null;
+               }
+               try {
+                       if (scrOnStart != null) {
+                               synchronized (scrOnStart) {
+                                       scrOnStart.close();
+                                       scrOnStart = new Script("conf/onStart", this, true);
+                               }
+                       } else {
+                               scrOnStart = new Script("conf/onStart", this, true);
+                       }
+               } catch (Exception e) {
+                       scrOnStart = null;
+               }
+               try {
+                       if (scrOnDeath != null) {
+                               synchronized (scrOnDeath) {
+                                       scrOnDeath.close();
+                                       scrOnDeath = new Script("conf/onDeath", this, true);
+                               }
+                       } else {
+                               scrOnDeath = new Script("conf/onDeath", this, true);
+                       }
+               } catch (Exception e) {
+                       scrOnDeath = null;
+               }
+               try {
+                       if (scrOnLogOut != null) {
+                               synchronized (scrOnLogOut) {
+                                       scrOnLogOut.close();
+                                       scrOnLogOut = new Script("conf/onLogOut", this, true);
+                               }
+                       } else {
+                               scrOnLogOut = new Script("conf/onLogOut", this, true);
+                       }
+               } catch (Exception e) {
+                       scrOnLogOut = null;
+               }
+
+               File f = new File("tileScriptMap");
+               if (f.exists()) {
+                       // Load tile scripts throuhg indirection
+                       try {
+                               Properties props = new Properties();
+                               try (FileInputStream fis = new FileInputStream(f)) {
+                                       props.load(fis);
+
+                                       for (Entry e : props.entrySet()) {
+                                               String key = (String) e.getKey();
+                                               String val = (String) e.getValue();
+
+                                               HashMap<Integer, Script> target = null;
+                                               String path = null;
+                                               String id = null;
+                                               if (key.startsWith("move.")) {
+                                                       target = tileCanMove;
+                                                       path = "defTileScripts/";
+                                                       id = key.substring(5);
+                                               } else if (key.startsWith("see.")) {
+                                                       target = tileCanSee;
+                                                       path = "defTileActions/";
+                                                       id = key.substring(4);
+                                               } else if (key.startsWith("action.")) {
+                                                       target = tileAction;
+                                                       path = "defTileSeeScripts/";
+                                                       id = key.substring(7);
+                                               }
+                                               if (target != null) {
+                                                       try {
+                                                               target.put(Integer.valueOf(id), new Script(path + val, this, true));
+                                                       } catch (Exception x) {
+                                                       }
+                                               }
+                                       }
+                               }
+                       } catch (IOException x) {
+                       }
+               } else {
+                       // Load Tile Scripts
+                       loadTileScripts(tileCanMove, "defTileScripts/");
+                       loadTileScripts(tileAction, "defTileActions/");
+                       loadTileScripts(tileCanSee, "defTileSeeScripts/");
+               }
+       }
+
+       void loadTileScripts(HashMap<Integer, Script> scripts, String path) {
+               try {
+                       int i;
+                       for (Script s : scripts.values()) {
+                               s.close();
+                       }
+                       scripts.clear();
+                       // FIXME: just try to load known tile sizes, we know how many tiles we have
+                       for (i = 0; true; i++) {
+                               try {
+                                       scripts.put(i, new Script(path + i, this, true));
+                               } catch (Exception e) {
+                                       break;
+                               }
+                       }
+               } catch (Exception e) {
+               }
+       }
+
+       public synchronized long getID() {
+               nextid++;
+               return nextid;
+       }
+
+       public void chatMessage(String msg, String from) {
+               from = from.toLowerCase();
+               log.printMessage(Log.ALWAYS, msg);
+               for (LivingThing lt : playersByName.values()) {
+                       if (!lt.ignoreList.contains(from)) {
+                               lt.chatMessage(msg);
+                       }
+               }
+       }
+
+       public void chatMessage(String inMessage, int locx, int locy, String strFrom) {
+               strFrom = strFrom.toLowerCase();
+               LivingThing thnStore;
+               log.printMessage(Log.ALWAYS, inMessage);
+
+               for (TileMap.MapData md : map.range(locx, locy, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       thnStore = (LivingThing) o;
+                                       if (thnStore.isPlayer()
+                                                       && !thnStore.ignoreList.contains(strFrom)) {
+                                               thnStore.chatMessage(inMessage);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void chatMessage(String msg, String clan, String from) {
+               from = from.toLowerCase();
+               log.printMessage(Log.ALWAYS, msg);
+               for (LivingThing lt : playersByName.values()) {
+                       if (lt.clan.equals(clan)
+                                       && !lt.ignoreList.contains(from)) {
+                               lt.chatMessage(msg);
+                       }
+               }
+       }
+
+       public void refreshEntities(LivingThing refresh) {
+               LinkedList<DuskObject> newEntities = new LinkedList<>();
+
+               for (TileMap.MapData md : map.range(refresh.x, refresh.y, viewrange)) {
+                       if (!md.entities.isEmpty()
+                                       && canSeeTo(refresh, md.x, md.y)) {
+                               for (DuskObject o : md.entities) {
+                                       newEntities.add(o);
+                                       //old = thnRefresh.removeEntity(objStore.ID);
+                                       //for (i4 = 0; i4 < thnRefresh.nearEntities.size(); i4++) {
+                                       //      objStore2 = (DuskObject) thnRefresh.nearEntities.elementAt(i4);
+                                       //      if (objStore2 == objStore) {
+                                       //              thnRefresh.nearEntities.removeElementAt(i4);
+                                       //              i4 = -1;
+                                       //              break;
+                                       //      }
+                                       //}
+                                       if (o.isPlayerMerchant()) {
+                                               PlayerMerchant shop = (PlayerMerchant) o;
+                                               if (refresh.x == shop.x && refresh.y == shop.y) {
+                                                       //strResult = (char) 17 + "";
+                                                       StringBuilder sb = new StringBuilder();
+                                                       for (String name : shop.vctItems.keySet()) {
+                                                               LinkedList<Item> vctStore = shop.vctItems.get(name);
+                                                               Item item = (Item) vctStore.element();
+                                                               int intCost = (item.intCost * 3) / 4;
+
+                                                               if (refresh.name.equalsIgnoreCase(shop.strOwner)) {
+                                                                       intCost = 0;
+                                                               }
+                                                               sb.append(intCost + "gp)" + name + "\n");
+                                                       }
+                                                       sb.append(".\n");
+                                                       refresh.send(MessageType.UpdateMerchant, sb.toString());
+                                                       refresh.updateSell();
+                                               }
+                                       }
+                                       if (o.isMerchant()) {
+                                               Merchant merchant = (Merchant) o;
+                                               if (refresh.x == merchant.x && refresh.y == merchant.y) {
+                                                       if (true) {
+                                                               StringBuilder sb = new StringBuilder();
+                                                               //strResult = (char) 17 + "";
+                                                               if (refresh.getFollowing() != null && refresh.getFollowing().isPet()) {
+                                                                       for (int i5 = 0; i5 < merchant.items.size(); i5++) {
+                                                                               String itemname = (String) merchant.items.get(i5);
+                                                                               Item item = getItem(itemname);
+                                                                               if (item != null) {
+                                                                                       sb.append(item.intCost).append("gp)").append(itemname).append("\n");
+                                                                               } else if (itemname.equals("pet")) {
+                                                                                       sb.append(petcost).append("gp)").append(itemname).append("\n");
+                                                                               } else {
+                                                                                       sb.append(traincost).append("exp)").append(itemname).append("\n");
+                                                                                       sb.append(traincost).append("exp)").append(refresh.getFollowing().name).append(":").append(itemname).append("\n");
+                                                                               }
+                                                                       }
+                                                               } else {
+                                                                       for (int i5 = 0; i5 < merchant.items.size(); i5++) {
+                                                                               String itemname = (String) merchant.items.get(i5);
+                                                                               Item item = getItem(itemname);
+                                                                               if (item != null) {
+                                                                                       sb.append(item.intCost).append("gp)").append(itemname).append("\n");
+                                                                               } else if (itemname.equals("pet")) {
+                                                                                       sb.append(petcost).append("gp)").append(itemname).append("\n");
+                                                                               } else {
+                                                                                       sb.append(traincost).append("exp)").append(itemname).append("\n");
+                                                                               }
+                                                                       }
+                                                               }
+                                                               sb.append(".\n");
+                                                               refresh.send(MessageType.UpdateMerchant, sb.toString());
+                                                               refresh.updateSell();
+                                                       } else {
+                                                               HashMap<String, TransactionItem> items = new HashMap<>();
+                                                               for (String itemname : merchant.items) {
+                                                                       TransactionItem titem = items.get(itemname);
+                                                                       if (titem == null) {
+                                                                               Item item = getItem(itemname);
+                                                                               if (item != null) {
+                                                                                       titem = new TransactionItem(itemname, 1, item.intCost, "gp");
+                                                                               } else if (itemname.equals("pet")) {
+                                                                                       titem = new TransactionItem(itemname, 1, petcost, "gp");
+                                                                               } else {
+                                                                                       if (refresh.getFollowing() != null && refresh.getFollowing().isPet()) {
+                                                                                               titem = new TransactionItem(refresh.getFollowing().name + ":" + itemname, 1, traincost, "exp");
+                                                                                               items.put(titem.name, titem);
+                                                                                       }
+                                                                                       titem = new TransactionItem(itemname, 1, traincost, "exp");
+                                                                                       //sb.append(traincost).append("exp)").append(itemname).append("\n");
+                                                                                       //sb.append(traincost).append("exp)").append(refresh.getFollowing().name).append(":").append(itemname).append("\n");
+                                                                               }
+                                                                               items.put(titem.name, titem);
+                                                                       } else {
+                                                                               titem.count++;
+                                                                       }
+                                                               }
+                                                               refresh.send(new ServerMessage.ItemsMessage(MessageType.UpdateMerchant, new ArrayList<>(items.values())));
+                                                               refresh.updateSell();
+                                                       }
+                                               }
+                                               //if (old == null) { //i4 != -1
+                                               //      if (!objStore.isLivingThing()
+                                               //                      || canSeeLivingThing(thnRefresh, (LivingThing) objStore)) {
+                                               //              thnRefresh.send(MessageType.AddEntity, objStore.toEntity());
+                                               //      }
+                                               //}
+                                       }
+                               }
+                       }
+               }
+               // Remove those left
+               //for (DuskObject o: thnRefresh.nearEntities) {
+               //      thnRefresh.send(MessageType.RemoveEntity, o.ID + "\n");
+               //}
+               //thnRefresh.nearEntities = vctNewEntities;
+               refresh.setEntities(newEntities);
+       }
+
+       public void addEntity(DuskObject add) {
+               for (TileMap.MapData md : map.range(add.x, add.y, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       if (lt.isPlayer()) {
+                                               // FIXME: see if this can be merged with updateEntity() above
+
+                                               if (canSeeTo(lt, add.x, add.y)) {
+                                                       if ((!add.isLivingThing()
+                                                                       || canSeeLivingThing(lt, (LivingThing) add))) {
+                                                               lt.addEntity(add);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void cleanup() {
+               log.printMessage(Log.INFO, "Starting cleanup.");
+               for (TileMap.MapData md : map) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       if (lt.isPlayer()) {
+                                               if (!playersByName.containsKey(lt.name)) {
+                                                       log.printMessage(Log.INFO, "**found defunct player at " + md.x + "," + md.y + " during cleanup.");
+                                                       removeDuskObject(lt);
+                                                       lt.battle = null;
+                                                       lt.isStopped = true;
+                                               }
+                                       }
+                                       if (lt.isPet()) {
+                                               if (!petList.contains(lt)) {
+                                                       log.printMessage(Log.INFO, "**found defunct pet at " + md.x + "," + md.y + " during cleanup.");
+                                                       removeDuskObject(lt);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               log.printMessage(Log.INFO, "Finished cleanup.");
+       }
+
+       void notifyRemoved(DuskObject remove) {
+               for (TileMap.MapData md : map.range(remove.x, remove.y, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+
+                                       if (lt.isPlayer()) {
+                                               if (canSeeTo(lt, remove.x, remove.y)) {
+                                                       lt.removeEntity(remove.ID);
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void newBattle(LivingThing pla1, LivingThing pla2) {
+               if (pla2 == null) {
+                       return;
+               }
+               if (pla1.isPet()) {
+                       pla1.chatMessage("Pets cannot lead battles.");
+                       return;
+               }
+               if (pla1.battle != null) {
+                       pla1.chatMessage("You're already fighting!");
+                       return;
+               }
+               if (pla1 == pla2) {
+                       pla1.chatMessage("You can't fight yourself!");
+                       return;
+               }
+               if (pla2.isPet()) {
+                       pla1.chatMessage("You can't attack pets.");
+                       return;
+               }
+//             if (Math.abs(pla1.intLocX - pla2.intLocX) + Math.abs(pla1.intLocY - pla2.intLocY) > 1)
+               if (Math.abs(pla1.x - pla2.x) + Math.abs(pla1.y - pla2.y) > pla1.getRangeWithBonus()) {
+                       System.out.println("mob range = " + Math.abs(pla1.x - pla2.x) + Math.abs(pla1.y - pla2.y));
+                       System.out.println("player range = " + pla1.getRangeWithBonus());
+                       pla1.chatMessage("They're too far away.");
+                       return;
+               }
+               if (scrCanAttack != null) {
+                       synchronized (scrCanAttack) {
+                               scrCanAttack.varVariables.clearVariables();
+                               scrCanAttack.varVariables.addVariable("attacking", pla1);
+                               scrCanAttack.varVariables.addVariable("attacked", pla2);
+                               if (!scrCanAttack.rewindAndParseScript()) {
+                                       pla1.chatMessage("You can't attack them.");
+                                       return;
+                               }
+                       }
+               }
+               // Check if the attacked is following the attacker
+               LivingThing thnStore = pla2;
+               while (thnStore != null) {
+                       if (pla1 == thnStore) {
+                               pla1.chatMessage("You can't attack a member of your group.");
+                               return;
+                       }
+                       if (thnStore.isPlayer() && !pla1.isMob()) {
+                               if (thnStore.clan == null || thnStore.clan.equalsIgnoreCase("none")) {
+                                       pla1.chatMessage("You can't fight them.");
+                                       return;
+                               }
+                       }
+                       thnStore = thnStore.getMaster();
+               }
+               // Check if the attacker is following the attacked
+               thnStore = pla2;
+               while (thnStore != null) {
+                       if (pla1 == thnStore) {
+                               pla1.chatMessage("You can't attack a member of your group.");
+                               return;
+                       }
+                       if (thnStore.isPlayer() && !pla1.isMob()) {
+                               if (thnStore.clan == null || thnStore.clan.equalsIgnoreCase("none")) {
+                                       pla1.chatMessage("You can't fight them.");
+                                       return;
+                               }
+                       }
+                       thnStore = thnStore.getFollowing();
+               }
+               if (pla2.battle == null) {
+                       if ((pla1.isPlayer() && pla2.isPlayer()) && (pla1.clan.equals("none") || pla2.clan.equals("none"))) {
+                               pla1.chatMessage("Players who are not in clans cannot fight other players.");
+                               return;
+                       }
+                       if (pla2.isPlayer() && overMerchant(pla2.x, pla2.y) != null) {
+                               pla1.chatMessage("You cannot attack players who are shopping.");
+                               return;
+                       }
+                       if (pla2.isPlayer() && overPlayerMerchant(pla2.x, pla2.y) != null) {
+                               pla1.chatMessage("You cannot attack players who are shopping.");
+                               return;
+                       }
+                       // FIXME: locks?
+                       battleList.add(new Battle(pla1, pla2, this));
+                       return;
+               } else {
+                       if (pla2.battleSide == 1) {
+                               thnStore = pla1;
+                               while (thnStore != null) {
+                                       if (thnStore.battle == null) {
+                                               pla2.battle.addToBattle(thnStore, 2);
+                                       }
+                                       thnStore = thnStore.getFollowing();
+                               }
+                               thnStore = pla1.getMaster();
+                               while (thnStore != null) {
+                                       if (thnStore.battle == null) {
+                                               pla2.battle.addToBattle(thnStore, 2);
+                                       }
+                                       thnStore = thnStore.getMaster();
+                               }
+                       } else {
+                               thnStore = pla1;
+                               while (thnStore != null) {
+                                       if (thnStore.battle == null) {
+                                               pla2.battle.addToBattle(thnStore, 1);
+                                       }
+                                       thnStore = thnStore.getFollowing();
+                               }
+                               thnStore = pla1.getMaster();
+                               while (thnStore != null) {
+                                       if (thnStore.battle == null) {
+                                               pla2.battle.addToBattle(thnStore, 1);
+                                       }
+                                       thnStore = thnStore.getMaster();
+                               }
+                       }
+//                     pla2.batBattle.chatMessage("\t"+pla1.strName+" has joined the battle.");
+                       return;
+               }
+       }
+
+       // Not used
+       @Deprecated
+       public Sign getSign(String inName) {
+               int i;
+               Sign sgnStore;
+               for (i = 0; i < signList.size(); i++) {
+                       sgnStore = (Sign) signList.get(i);
+                       if (inName.equals(sgnStore.name)) {
+                               return sgnStore;
+                       }
+               }
+               return null;
+       }
+
+       public LivingThing getPet(String name) {
+               // FIXME: hash map?
+               for (LivingThing pet : petList) {
+                       if (name.equalsIgnoreCase(pet.name)) {
+                               return pet;
+                       }
+               }
+               return null;
+       }
+
+       public LivingThing getPlayer(String name) {
+               name = name.toLowerCase();
+
+               return playersByName.get(name);
+       }
+
+       public Faction getFaction(String name) {
+               Faction faction;
+
+               faction = factionMap.get(name);
+               if (faction == null) {
+                       faction = new Faction(name, this);
+                       factionMap.put(name, faction);
+               }
+               return faction;
+       }
+
+       public LivingThing getMobFromVct(String inName) {
+               // FIXME: hash map?
+               synchronized (mobList) {
+                       for (Mob mob : mobList) {
+                               if (mob.name.equals(inName)) {
+                                       return mob;
+                               }
+                       }
+               }
+               return null;
+       }
+
+       // FIXME: io on prop as per Item
+       Prop getProp(String strName) {
+               Prop prpStore = null;
+               try {
+                       RandomAccessFile rafPropDef = new RandomAccessFile("defProps/" + strName, "r");
+                       prpStore = new Prop(getID(), strName);
+                       String strStore = rafPropDef.readLine();
+                       while (!(strStore == null || strStore.equals("."))) {
+                               if (strStore.equalsIgnoreCase("description")) {
+                                       prpStore.description = rafPropDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("image")) {
+                                       prpStore.intImage = Integer.parseInt(rafPropDef.readLine());
+                               }
+                               strStore = rafPropDef.readLine();
+                       }
+                       rafPropDef.close();
+               } catch (Exception e) {
+                       log.printError("getProp():While trying to get prop \"" + strName + "\"", e);
+               }
+               return prpStore;
+       }
+
+       // Unused
+       @Deprecated
+       Prop getPropFromVct(String inName) {
+               try {
+                       int i = 0;
+                       Prop prpStore;
+                       while (true) {
+                               prpStore = (Prop) propList.get(i);
+                               if (prpStore.name.equals(inName)) {
+                                       return prpStore;
+                               }
+                               i++;
+                       }
+               } catch (Exception e) {
+                       log.printError("getPropFromVct():While trying to get prop \"" + inName + "\"", e);
+               }
+               return null;
+       }
+
+       // Unused
+       @Deprecated
+       Prop getPropFromVctAndRemove(String inName) {
+               try {
+                       int i = 0;
+                       Prop prpStore;
+                       while (true) {
+                               prpStore = (Prop) propList.get(i);
+                               if (prpStore.name.equals(inName)) {
+                                       //vctProps.remove(i);
+                                       removeDuskObject(prpStore);
+                                       return prpStore;
+                               }
+                               i++;
+                       }
+               } catch (Exception e) {
+                       log.printError("getPropFromVctAndRemove():While trying to get prop \"" + inName + "\"", e);
+               }
+               return null;
+       }
+
+       @Deprecated
+       public Condition getCondition(String inName) {
+               try {
+                       return Condition.getCondition(inName);
+               } catch (Exception e) {
+                       log.printError("getCondition():Parsing condition \"" + inName + "\"", e);
+               }
+               return null;
+       }
+
+       int getSpellPercent(String strName) {
+               try {
+                       RandomAccessFile rafSpell = new RandomAccessFile("defSpells/" + strName, "r");
+                       SpellGroup grpStore = getSpellGroup(rafSpell.readLine());
+                       rafSpell.close();
+                       return grpStore.getSpellPercent(strName);
+               } catch (Exception e) {
+                       log.printError("getSpellPercent():While trying to get info on spell \"" + strName + "\"", e);
+               }
+               return -1;
+       }
+
+       // FIXME: do i/o in SpellGroup
+       @Deprecated
+       public SpellGroup getSpellGroup(String strName) {
+               SpellGroup group;
+               String key = strName.toLowerCase();
+
+               group = spellGroupList.get(key);
+               if (group == null) {
+                       group = new SpellGroup(strName);
+                       try (RandomAccessFile rafSpellGroup = new RandomAccessFile("defSpellGroups/" + strName, "r")) {
+                               String strStore = rafSpellGroup.readLine();
+                               while (strStore != null && !strStore.equals("") && !strStore.equals(".")) {
+                                       group.vctSpells.add(strStore);
+                                       strStore = rafSpellGroup.readLine();
+                               }
+                               spellGroupList.put(key, group);
+                       } catch (IOException e) {
+                               log.printError("trying to read spell group file for \"" + strName + "\"", e);
+                               group = null;
+                       }
+               }
+               return group;
+       }
+
+       // FIXME: move this to Item
+       @Deprecated
+       public Item getItem(String inName) {
+               try {
+                       return Item.getItem(getID(), inName);
+               } catch (IOException ex) {
+                       log.printError("getItem():Parsing item \"" + inName + "\"", ex);
+                       return null;
+               }
+       }
+
+       // Appears unused
+       @Deprecated
+       Item getItemFromVct(String inName) {
+               try {
+                       int i;
+                       Item itmStore;
+                       StringTokenizer tokName = new StringTokenizer(inName, " ");
+                       String strStore = tokName.nextToken();
+                       i = Integer.parseInt(strStore);
+                       strStore = inName.substring(strStore.length() + 1, inName.length());
+                       itmStore = (Item) itemList.get(i);
+                       if (itmStore.name.equals(strStore)) {
+                               return itmStore;
+                       }
+               } catch (Exception e) {
+                       log.printError("getItemFromVct():For item \"" + inName + "\"", e);
+               }
+               return null;
+       }
+
+       // Appears unused
+       @Deprecated
+       Item getItemFromVctAndRemove(String inName) {
+               try {
+                       int i;
+                       Item itmStore;
+                       StringTokenizer tokName = new StringTokenizer(inName, " ");
+                       String strStore = tokName.nextToken();
+                       i = Integer.parseInt(strStore);
+                       strStore = inName.substring(strStore.length() + 1, inName.length());
+                       itmStore = (Item) itemList.get(i);
+                       if (itmStore.name.equals(strStore)) {
+                               //vctItems.remove(i);
+                               removeDuskObject(itmStore);
+                               return itmStore;
+                       }
+               } catch (Exception e) {
+                       log.printError("getItemFromVctAndRemove():For item \"" + inName + "\"", e);
+               }
+               return null;
+       }
+
+       void playSound(int sfxid, int locx, int locy) {
+               for (TileMap.MapData md : map.range(locx, locy, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       if (lt.isPlayer()) {
+                                               lt.playSFX(sfxid);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public boolean canMoveTo(int inLocX, int inLocY, LivingThing thnStore) {
+               int i;
+               LivingThing thnStore2;
+               Script scrStore;
+               boolean blnStore;
+
+               if (!map.inside(inLocX, inLocY))
+                       return false;
+
+               for (DuskObject o : map.getEntities(inLocX, inLocY, null)) {
+                       if (o.isLivingThing()) {
+                               thnStore2 = (LivingThing) o;
+                               if (!canMoveThrougLivingThing(thnStore, thnStore2))
+                                       return false;
+                       }
+               }
+               try {
+                       scrStore = new Script("defCanMoveScripts/" + inLocX + "_" + inLocY, this, false);
+                       scrStore.varVariables.addVariable("trigger", thnStore);
+                       blnStore = scrStore.rewindAndParseScript();
+                       scrStore.close();
+                       return blnStore;
+               } catch (Exception e) {
+               }
+               try {
+                       scrStore = (Script) tileCanMove.get((int) map.getTile(inLocX, inLocY));
+                       synchronized (scrStore) {
+                               scrStore.varVariables.clearVariables();
+                               scrStore.varVariables.addVariable("trigger", thnStore);
+                               blnStore = scrStore.rewindAndParseScript();
+                       }
+                       return blnStore;
+               } catch (Exception e) {
+                       //e.printStackTrace();
+               }
+               return false;
+       }
+
+       boolean canSee(int inLocX, int inLocY, LivingThing thnStore) {
+               int i;
+               LivingThing thnStore2;
+               DuskObject objStore = null;
+               Script scrStore;
+               boolean blnStore;
+               try {
+                       scrStore = new Script("defCanSeeScripts/" + inLocX + "_" + inLocY, this, false);
+                       scrStore.varVariables.addVariable("trigger", thnStore);
+                       blnStore = scrStore.rewindAndParseScript();
+                       scrStore.close();
+                       return blnStore;
+               } catch (Exception e) {
+               }
+               try {
+                       scrStore = (Script) tileCanSee.get((int) map.getTile(inLocX, inLocY));
+                       synchronized (scrStore) {
+                               scrStore.varVariables.clearVariables();
+                               scrStore.varVariables.addVariable("trigger", thnStore);
+                               blnStore = scrStore.rewindAndParseScript();
+                       }
+                       return blnStore;
+               } catch (Exception e) {
+               }
+               return false;
+       }
+
+       // TODO: Move this to map, then everything that uses it can be elsewhere
+       // Following by Randall Leeds and Tom Weingarten
+       // map/iterator version by notzed
+       public boolean canSeeTo(LivingThing thing, int destX, int destY) {
+               if (Math.abs(thing.x - destX) > viewrange || Math.abs(thing.y - destY) > viewrange) {
+                       return false;
+               }
+
+               if (!blnLineOfSight) {
+                       return true;
+               }
+
+               for (TileMap.MapData md : map.look(thing.x, thing.y, destX, destY)) {
+                       if (!canSee(md.x, md.y, thing))
+                               return false;
+               }
+               return true;
+               /*              
+                int tempX = thing.x;
+                int tempY = thing.y;
+
+                // TODO: put looking stuff on map
+                // TODO: put path finding on map
+                // FIXME: this exception stuff is just used for bounds checking ... not good
+                // FIXME: logic could be improved using directions
+                try {
+                while (!(Math.abs(tempX - destX) < 2 && Math.abs(tempY - destY) < 2)) {
+                if (Math.abs(tempX - destX) > Math.abs(tempY - destY)) {
+                if (tempX > destX) {
+                if (!(canSee(tempX - 1, tempY, thing))) {
+                return false;
+                }
+                tempX--;
+                } else {
+                if (!(canSee(tempX + 1, tempY, thing))) {
+                return false;
+                }
+                tempX++;
+                }
+                } else if (Math.abs(tempX - destX) < Math.abs(tempY - destY)) {
+                if (tempY > destY) {
+                if (!(canSee(tempX, tempY - 1, thing))) {
+                return false;
+                }
+                tempY--;
+                } else {
+                if (!(canSee(tempX, tempY + 1, thing))) {
+                return false;
+                }
+                tempY++;
+                }
+                } else {
+                if (tempX > destX && tempY > destY) {
+                if (!(canSee(tempX - 1, tempY - 1, thing))) {
+                return false;
+                }
+                tempX--;
+                tempY--;
+                } else if (tempX < destX && tempY < destY) {
+                if (!(canSee(tempX + 1, tempY + 1, thing))) {
+                return false;
+                }
+                tempX++;
+                tempY++;
+                } else if (tempX > destX && tempY < destY) {
+                if (!(canSee(tempX - 1, tempY + 1, thing))) {
+                return false;
+                }
+                tempX--;
+                tempY++;
+                } else {
+                if (!(canSee(tempX + 1, tempY - 1, thing))) {
+                return false;
+                }
+                tempX++;
+                tempY--;
+                }
+                }
+                }
+                } catch (Exception e) {
+                return false;
+                }
+
+                return true;
+                * */
+       }
+       //End contributed portion
+
+       public Merchant overMerchant(int x, int y) {
+               for (DuskObject o : map.getEntities(x, y, null)) {
+                       if (o.isMerchant()) {
+                               return (Merchant) o;
+                       }
+               }
+               return null;
+       }
+
+       public PlayerMerchant overPlayerMerchant(int x, int y) {
+               for (DuskObject o : map.getEntities(x, y, null)) {
+                       if (o.isPlayerMerchant()) {
+                               return (PlayerMerchant) o;
+                       }
+               }
+               return null;
+       }
+
+       synchronized void changeMap(int locx, int locy, short value) {
+               if (value < 0 || value > tileCanMove.size()) {
+                       log.printMessage(Log.INFO, "Invalid value passed to changeMap(" + locx + "," + locy + "," + value + ")");
+                       return;
+               }
+               if (!map.inside(locx, locy)) {
+                       log.printMessage(Log.INFO, "Invalid location to changeMap(" + locx + "," + locy + "," + value + ")");
+                       return;
+               }
+               map.setTile(locx, locy, value);
+               blnMapHasChanged = true;
+               updateMap(locx, locy);
+       }
+
+       synchronized void resizeMap(int x, int y) {
+               map.resize(x, y);
+               for (LivingThing lt : playersByName.values()) {
+                       lt.resizeMap();
+               }
+               blnMapHasChanged = true;
+       }
+
+       void saveMap() {
+               if (blnSavingGame) {
+                       return;
+               }
+               try {
+                       blnSavingGame = true;
+                       StringTokenizer tknStore;
+                       Mob mobStore;
+                       Item itmStore;
+                       Sign sgnStore;
+                       Merchant mrcStore;
+                       Prop prpStore;
+                       File deleteme;
+                       RandomAccessFile rafFile;
+                       int i,
+                                       i2;
+                       if (blnMapHasChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving map...");
+                               map.saveMap(new File("shortmap"));
+                               String strMapLog = "shortmap_redraw";
+                               PrintStream psMap = new PrintStream(new FileOutputStream(strMapLog, true), true);
+                               psMap.println("# Map Saved");
+                               psMap.close();
+                               blnMapHasChanged = false;
+                       }
+
+                       if (blnMobListChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving mobs...");
+                               synchronized (mobList) {
+                                       deleteme = new File("mobs");
+                                       deleteme.delete();
+                                       rafFile = new RandomAccessFile("mobs", "rw");
+                                       for (Mob mob : mobList) {
+                                               if (mob.blnOneUse == false) {
+                                                       if (mob.level == -1) {
+                                                               rafFile.writeBytes("mob2.3\n" + mob.name + "\n" + mob.originalX + "\n" + mob.originalY + "\n");
+                                                       } else {
+                                                               rafFile.writeBytes(mob.name + "\n" + mob.level + "\n" + mob.originalX + "\n" + mob.originalY + "\n");
+                                                       }
+                                               }
+                                       }
+                                       rafFile.close();
+                               }
+                               blnMobListChanged = false;
+                       }
+
+                       if (blnSignListChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving signs...");
+                               synchronized (signList) {
+                                       deleteme = new File("signs");
+                                       deleteme.delete();
+                                       rafFile = new RandomAccessFile("signs", "rw");
+                                       for (Sign sign : signList) {
+                                               rafFile.writeBytes(sign.strMessage + "\n" + sign.x + "\n" + sign.y + "\n");
+                                       }
+                                       rafFile.close();
+                               }
+                               blnSignListChanged = false;
+                       }
+
+                       if (blnMerchantListChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving merchants...");
+                               synchronized (merchantList) {
+                                       deleteme = new File("merchants");
+                                       deleteme.delete();
+                                       try (RandomAccessFile out = new RandomAccessFile("merchants", "rw")) {
+                                               // FIXME: i/o on object
+                                               for (Merchant m : merchantList) {
+                                                       out.writeBytes(m.x + "\n" + m.y + "\n");
+                                                       for (i2 = 0; i2 < m.items.size(); i2++) {
+                                                               out.writeBytes((String) m.items.get(i2) + "\n");
+                                                       }
+                                                       out.writeBytes("end\n");
+                                               }
+                                       }
+                               }
+                               blnMerchantListChanged = false;
+                       }
+
+                       if (blnPropListChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving props...");
+                               synchronized (propList) {
+                                       deleteme = new File("props");
+                                       deleteme.delete();
+                                       rafFile = new RandomAccessFile("props", "rw");
+                                       for (Prop prop : propList) {
+                                               rafFile.writeBytes(prop.name + "\n" + prop.x + "\n" + prop.y + "\n");
+                                       }
+                                       rafFile.close();
+                               }
+                               blnPropListChanged = false;
+                       }
+
+                       if (blnVariableListChanged) {
+                               log.printMessage(Log.ALWAYS, "Saving global variables...");
+                               synchronized (varVariables) {
+                                       deleteme = new File("globals");
+                                       deleteme.delete();
+                                       rafFile = new RandomAccessFile("globals", "rw");
+                                       for (Variable varStore : varVariables.vctVariables.values()) {
+                                               if (varStore.isString() || varStore.isNumber()) {
+                                                       rafFile.writeBytes(varStore.strName + "\n");
+                                                       rafFile.writeBytes(varStore.bytType + "\n");
+                                                       rafFile.writeBytes(varStore.objData + "\n");
+                                               }
+                                       }
+                                       rafFile.close();
+                               }
+                               blnVariableListChanged = false;
+                       }
+                       log.printMessage(Log.ALWAYS, "Saved game settings without error");
+               } catch (Exception e) {
+                       log.printError("saveMap():While saving game settings", e);
+               }
+               blnSavingGame = false;
+       }
+
+       void backupMap() {
+               try {
+                       StringTokenizer tknStore;
+                       Mob mobStore;
+                       Item itmStore;
+                       Sign sgnStore;
+                       Merchant mrcStore;
+                       Prop prpStore;
+                       synchronized (map) {
+                               File deleteme;
+                               RandomAccessFile rafFile;
+                               int i, i2;
+
+                               map.saveMap(new File("backup/shortmap.backup"));
+
+                               deleteme = new File("backup/mobs.backup");
+                               deleteme.delete();
+                               rafFile = new RandomAccessFile("backup/mobs.backup", "rw");
+                               synchronized (mobList) {
+                                       for (Mob mob : mobList) {
+                                               if (mob.blnOneUse == false) {
+                                                       tknStore = new StringTokenizer(mob.name, " ");
+                                                       rafFile.writeBytes(tknStore.nextToken() + "\n" + mob.level + "\n" + mob.originalX + "\n" + mob.originalY + "\n");
+                                               }
+                                       }
+                               }
+                               rafFile.close();
+
+                               deleteme = new File("backup/signs.backup");
+                               deleteme.delete();
+                               rafFile = new RandomAccessFile("backup/signs.backup", "rw");
+                               for (Sign sign : signList) {
+                                       rafFile.writeBytes(sign.strMessage + "\n" + sign.x + "\n" + sign.y + "\n");
+                               }
+                               rafFile.close();
+
+                               deleteme = new File("backup/merchants.backup");
+                               deleteme.delete();
+                               rafFile = new RandomAccessFile("backup/merchants.backup", "rw");
+                               for (Merchant m : merchantList) {
+                                       rafFile.writeBytes(m.x + "\n" + m.y + "\n");
+                                       for (i2 = 0; i2 < m.items.size(); i2++) {
+                                               rafFile.writeBytes((String) m.items.get(i2) + "\n");
+                                       }
+                                       rafFile.writeBytes("end\n");
+                               }
+                               rafFile.close();
+
+                               deleteme = new File("backup/props.backup");
+                               deleteme.delete();
+                               rafFile = new RandomAccessFile("backup/props.backup", "rw");
+                               for (Prop prop : propList) {
+                                       rafFile.writeBytes(prop.name + "\n" + prop.x + "\n" + prop.y + "\n");
+                               }
+                               rafFile.close();
+                       }
+                       log.printMessage(Log.ALWAYS, "Backed up game settings without error");
+               } catch (Exception e) {
+                       log.printError("backupMap():While backing up settings", e);
+               }
+       }
+
+       @Deprecated
+       DuskObject getDuskObject(int x, int y, String name) {
+               //synchronized (entities) {
+               //      return DuskObject.find(entities[x][y], name);
+               //}
+               for (DuskObject o : map.getEntities(x, y, null)) {
+                       if (o.name.equalsIgnoreCase(name))
+                               return o;
+
+               }
+               return null;
+       }
+
+       // must have objEntities locked
+       @Deprecated
+       private void pushDuskObject(DuskObject o) {
+               map.addEntity(o);
+       }
+
+       @Deprecated
+       private void popDuskObject(DuskObject o) {
+               map.removeEntity(o);
+       }
+
+       public void addDuskObject(DuskObject obj) {
+               if (obj.isLivingThing()) {
+                       LivingThing lt = (LivingThing) obj;
+                       if (!lt.isLoaded) {
+                               return;
+                       }
+                       if (obj instanceof Mob) {
+                               synchronized (mobList) {
+                                       mobList.add((Mob) obj);
+                               }
+                               blnMobListChanged = true;
+                       } else if (lt.isPet()) {
+                               petList.add(lt);
+                       }
+               } else if (obj.isItem()) {
+                       itemList.add((Item) obj);
+               } else if (obj.isSign()) {
+                       signList.add((Sign) obj);
+                       blnSignListChanged = true;
+               } else if (obj.isMerchant()) {
+                       merchantList.add((Merchant) obj);
+                       blnMerchantListChanged = true;
+               } else if (obj.isProp()) {
+                       propList.add((Prop) obj);
+                       blnPropListChanged = true;
+               }
+
+
+               pushDuskObject(obj);
+               addEntity(obj);
+       }
+
+       /**
+        * When a mob is killed, it isn't really removed, but the player needs
+        * to know about it.
+        *
+        * This 'cheats' by removing it from the game but temporarily
+        * corrupting the mob index.
+        *
+        * @param obj
+        */
+       public void mobKilled(Mob obj) {
+               notifyRemoved(obj);
+               popDuskObject(obj);
+       }
+
+       public void removeDuskObject(DuskObject obj) {
+               if (obj.isLivingThing()) {
+                       LivingThing lt = (LivingThing) obj;
+                       if (!lt.isLoaded) {
+                               return;
+                       }
+                       if (lt.isMob()) {
+                               synchronized (mobList) {
+                                       mobList.remove(obj);
+                               }
+                               blnMobListChanged = true;
+                       } else if (lt.isPet()) {
+                               petList.remove(obj);
+                       }
+               } else if (obj.isItem()) {
+                       itemList.remove(obj);
+               } else if (obj.isSign()) {
+                       signList.remove(obj);
+                       blnSignListChanged = true;
+               } else if (obj.isMerchant()) {
+                       merchantList.remove(obj);
+                       blnMerchantListChanged = true;
+               } else if (obj.isProp()) {
+                       propList.remove(obj);
+                       blnPropListChanged = true;
+               }
+
+               notifyRemoved(obj);
+               popDuskObject(obj);
+       }
+
+       public Iterable<TileMap.MapData> visibleMap(int x, int y) {
+               return map.range(x, y, viewrange);
+       }
+
+       /**
+        * Move a living thing, updating any other living things within range
+        *
+        * @param thing
+        * @param inlocx
+        * @param inlocy
+        * @param dir
+        */
+       // FIXME: now i think this probably needs to be moved back to livingthing ...
+       public void moveDuskObject(LivingThing thing, int inlocx, int inlocy, MessageType dir) {
+               for (TileMap.MapData md : map.range(thing.x, thing.y, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       if (lt.isPlayer()) {
+                                               boolean canSee = canSeeTo(lt, inlocx, inlocy)
+                                                               && (!thing.isLivingThing()
+                                                               || canSeeLivingThing(lt, thing));
+
+                                               if (canSee) {
+                                                       // Add/update it if now visible
+                                                       lt.addEntity(thing);
+                                                       lt.send(dir, thing.ID + "\n");
+                                               } else {
+                                                       // Remove it if it isn't
+                                                       lt.removeEntity(thing.ID);
+                                               }
+                                       } else if (lt.isMob()) {
+                                               // Is this true?
+                                               Mob thnMob = (Mob) lt;
+                                               thnMob.blnCanSeePlayer = true;
+                                       }
+                               }
+                       }
+               }
+               // Move it from cell to cell
+               popDuskObject(thing);
+               thing.x = inlocx;
+               thing.y = inlocy;
+               pushDuskObject(thing);
+               //addDuskObject(objIn);
+       }
+
+       /**
+        * Find a visible object of the given name.
+        *
+        * Name may also be the id.
+        *
+        * @param thing
+        * @param name
+        * @return
+        */
+       public DuskObject findVisibleObject(LivingThing thing, String name) {
+               int number = 0;
+               int byid = -1;
+
+               // First see if this finding an object by unique id.
+               // Since .. the server and client have different ideas about "id numbers" (FFS)
+               try {
+                       byid = Integer.valueOf(name);
+                       number = 0;
+               } catch (NumberFormatException e) {
+               }
+
+               if (byid == -1) {
+                       int i = name.indexOf(".");
+                       if (i != -1) {
+                               try {
+                                       number = Integer.parseInt(name.substring(0, i));
+                                       name = name.substring(i + 1, name.length());
+                               } catch (NumberFormatException e) {
+                                       number = 0;
+                               }
+                       }
+               }
+               //Search surrounding area
+
+               for (TileMap.MapData md : map.range(thing.x, thing.y, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (byid == o.ID
+                                               || (byid == -1 && o.name.equalsIgnoreCase(name))) {
+                                       if ((!o.isLivingThing()
+                                                       || canSeeLivingThing(thing, (LivingThing) o))
+                                                       && canSeeTo(thing, o.x, o.y)) {
+                                               if (number == 0) {
+                                                       return o;
+                                               } else {
+                                                       number--;
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               return null;
+       }
+
+       void updateMap(int locx, int locy) {
+               for (TileMap.MapData md : map.range(locx, locy, viewrange)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       if (lt.isPlayer()) {
+                                               lt.updateMap();
+                                       }
+                               }
+                       }
+               }
+       }
+
+       public void run() {
+               log.printMessage(Log.ALWAYS, "Mob ticks = " + lngMobTicks);
+               log.printMessage(Log.ALWAYS, "Player ticks = " + lngPlayerTicks);
+               log.printMessage(Log.ALWAYS, "Starting Ticks");
+               int tick = 0,
+                               i;
+               LivingThing thnStore,
+                               thnStore2;
+               Battle batStore;
+               long lngTime = System.currentTimeMillis(),
+                               lngPause = 0;
+               while (true) {
+                       try {
+                               //250 milliseconds per tick
+                               lngPause = lngPlayerTicks - (System.currentTimeMillis() - lngTime);
+                               if (lngPause > 0) {
+                                       Thread.currentThread().sleep(lngPause);
+                               }
+                               lngTime = System.currentTimeMillis();
+                               if (tick % 73 == 0) {
+                                       for (LivingThing pet : petList) {
+                                               if (pet.battle == null) {
+                                                       if (pet.isSleeping) {
+                                                               pet.hp += 3 + (pet.cons + pet.consbon);
+                                                               if (pet.hp > (pet.maxhp + pet.hpbon)) {
+                                                                       pet.hp = (pet.maxhp + pet.hpbon);
+                                                               }
+                                                               pet.mp += 3 + (pet.wisd + pet.wisdbon);
+                                                               if (pet.mp > (pet.maxmp + pet.mpbon)) {
+                                                                       pet.mp = (pet.maxmp + pet.mpbon);
+                                                               }
+                                                       } else {
+                                                               pet.hp += 1 + ((pet.cons + pet.consbon) / 2);
+                                                               if (pet.hp > (pet.maxhp + pet.hpbon)) {
+                                                                       pet.hp = (pet.maxhp + pet.hpbon);
+                                                               }
+                                                               pet.mp += 1 + ((pet.wisd + pet.wisdbon) / 2);
+                                                               if (pet.mp > (pet.maxmp + pet.mpbon)) {
+                                                                       pet.mp = (pet.maxmp + pet.mpbon);
+                                                               }
+                                                       }
+                                               }
+                                               if (pet.getMaster() != null) {
+                                                       if (!pet.getMaster().isWorking) {
+                                                               pet.close();
+                                                               continue;
+                                                       }
+                                                       boolean blnTmpShouldSave = pet.isSaveNeeded;
+                                                       pet.getMaster().updateStats();
+                                                       pet.isSaveNeeded = blnTmpShouldSave;
+                                               } else {
+                                                       pet.close();
+                                                       continue;
+                                               }
+                                               pet.savePlayer();
+                                       }
+                               }
+                               for (LivingThing pet : petList) {
+                                       pet.moveTick();
+                               }
+                               //Following code submitted by Randall Leeds, revised by Tom Weingarten:
+                               for (LivingThing lt : playersByName.values()) {
+                                       if (!lt.isWorking) {
+                                               //thnStore.closeNoMsgPlayer();
+                                               continue;
+                                       }
+                                       if (!lt.isSaveable) {
+                                               continue;
+                                       }
+                                       if (lt.noChannel > 0 && tick % 4 == 0) {
+                                               lt.noChannel--;
+                                       }
+                                       lt.moveTick();
+                                       if (tick % 73 == 0) {
+                                               if (lt.battle == null) {
+                                                       if (lt.isSleeping) {
+                                                               lt.hp += 3 + (lt.cons + lt.consbon);
+                                                               if (lt.hp > (lt.maxhp + lt.hpbon)) {
+                                                                       lt.hp = (lt.maxhp + lt.hpbon);
+                                                               }
+                                                               lt.mp += 3 + (lt.wisd + lt.wisdbon);
+                                                               if (lt.mp > (lt.maxmp + lt.mpbon)) {
+                                                                       lt.mp = (lt.maxmp + lt.mpbon);
+                                                               }
+                                                       } else {
+                                                               lt.hp += 1 + ((lt.cons + lt.consbon) / 2);
+                                                               if (lt.hp > (lt.maxhp + lt.hpbon)) {
+                                                                       lt.hp = (lt.maxhp + lt.hpbon);
+                                                               }
+                                                               lt.mp += 1 + ((lt.wisd + lt.wisdbon) / 2);
+                                                               if (lt.mp > (lt.maxmp + lt.mpbon)) {
+                                                                       lt.mp = (lt.maxmp + lt.mpbon);
+                                                               }
+                                                       }
+                                                       lt.updateInfo();
+                                                       lt.savePlayer();
+                                               }
+                                       }
+                               }
+                               //End of code submitted by Randall Leeds
+
+                               if (tick % 10 == 0) {
+                                       for (i = 0; i < battleList.size(); i++) {
+                                               batStore = (Battle) battleList.get(i);
+                                               if (batStore.blnRunning == false) {
+                                                       battleList.remove(i);
+                                                       i--;
+                                               } else {
+                                                       batStore.run();
+                                               }
+                                       }
+                               }
+                               if (tick > 72) {
+                                       tick = 0;
+                                       synchronized (mobList) {
+                                               for (Mob mob : mobList) {
+                                                       if (mob.battle == null) {
+                                                               // FIXME: magic number
+                                                               if (mob.x != -6) {
+                                                                       mob.hp += 1 + (mob.cons / 2);
+                                                                       if (mob.hp > mob.maxhp) {
+                                                                               mob.hp = mob.maxhp;
+                                                                       }
+                                                                       mob.mp += 1 + (mob.wisd / 2);
+                                                                       if (mob.mp > mob.maxmp) {
+                                                                               mob.mp = mob.maxmp;
+                                                                       }
+                                                               } else {
+                                                                       mob.hp++;
+                                                                       if (mob.hp > 0) {
+                                                                               mob.hp = mob.maxhp;
+                                                                               mob.mp = mob.maxmp;
+                                                                               mob.changeLocBypass(mob.originalX, mob.originalY);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       for (Faction f : factionMap.values()) {
+                                               f.saveFactionData();;
+                                       }
+                               }
+                               tick++;
+                       } catch (Exception e) {
+                               log.printError("DuskEngine.run():at ticks", e);
+                       }
+               }
+       }
+
+       /**
+        * Script helpers
+        */
+       public boolean canSeeLivingThing(LivingThing seeing, LivingThing seen) {
+               if (scrCanSeeLivingThing != null) {
+                       synchronized (scrCanSeeLivingThing) {
+                               scrCanSeeLivingThing.varVariables.clearVariables();
+                               scrCanSeeLivingThing.varVariables.addVariable("seeing", seeing);
+                               scrCanSeeLivingThing.varVariables.addVariable("seen", seen);
+                               return scrCanSeeLivingThing.rewindAndParseScript();
+                       }
+               } else {
+                       return true;
+               }
+       }
+
+       public boolean canMoveThrougLivingThing(LivingThing moving, LivingThing blocking) {
+               if (scrCanMoveThroughLivingThing != null) {
+                       synchronized (scrCanMoveThroughLivingThing) {
+                               scrCanMoveThroughLivingThing.varVariables.clearVariables();
+                               scrCanMoveThroughLivingThing.varVariables.addVariable("moving", moving);
+                               scrCanMoveThroughLivingThing.varVariables.addVariable("blocking", blocking);
+                               return scrCanMoveThroughLivingThing.rewindAndParseScript();
+                       }
+               } else {
+                       return true;
+               }
+       }
+
+       public void onStart(LivingThing trigger) {
+               try {
+                       if (scrOnStart != null) {
+                               synchronized (scrOnStart) {
+                                       scrOnStart.varVariables.clearVariables();
+                                       scrOnStart.varVariables.addVariable("trigger", trigger);
+                                       scrOnStart.runScript();
+                               }
+                       }
+               } catch (Exception e) {
+               }
+       }
+
+       /**
+        * Temporarily ban an ip address
+        *
+        * @param strIP
+        */
+       public void banAddress(String strIP) {
+               synchronized (bannedIPMap) {
+                       bannedIPMap.put(strIP.toLowerCase(), System.currentTimeMillis());
+               }
+       }
+
+       public boolean isBanned(String ip) {
+               synchronized (bannedIPMap) {
+                       return bannedIPMap.containsKey(ip.toLowerCase());
+               }
+       }
+
+       public void clearBanned() {
+               synchronized (bannedIPMap) {
+                       bannedIPMap.clear();;
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/DuskServer.java b/DuskServer/src/duskz/server/DuskServer.java
new file mode 100644 (file)
index 0000000..6612f00
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Special thanks to:
+ * Randall Leeds
+ * Vittorio Alberto Floris
+ * Ian Macphail
+ * 
+ * Changes
+ */
+package duskz.server;
+
+import duskz.server.entity.LivingThing;
+import java.net.Socket;
+import java.net.ServerSocket;
+
+/**
+ * DuskServer contains the main method for the game.
+ * It handles incoming network connections and passes
+ * them to DuskEngine.
+ *
+ * @author Tom Weingarten
+ */
+public class DuskServer implements Runnable {
+
+       ServerSocket srvServer;
+       Socket sckStore;
+       DuskEngine engGame = null;
+       TrackerThread tracker = null;
+       SaveThread savThread = null;
+       TickThread ticks = null;
+       Thread thrEngine = null,
+                       thrTracker = null,
+                       thrSave = null,
+                       thrTicks = null;
+
+       /**
+        * Creates a new DuskServer object;
+        */
+       public static void main(String args[]) {
+               System.out.println("Loading...");
+               DuskServer MainServer = new DuskServer();
+               Thread thrAccept = new Thread(MainServer);
+               thrAccept.setName("DuskServer");
+               System.out.println("Ready for connections.");
+               thrAccept.start();
+       }
+
+       /**
+        * Creates a DuskEngine object, then a ServerSocket object, then
+        * starts a new thread to accept incoming connections.
+        */
+       public DuskServer() {
+               engGame = new DuskEngine();
+               thrEngine = new Thread(engGame);
+               thrEngine.setName("DuskEngine");
+               thrEngine.start();
+               if (engGame.tracker) {
+                       tracker = new TrackerThread(engGame);
+                       thrTracker = new Thread(tracker);
+                       thrTracker.setName("Tracker");
+                       thrTracker.start();
+               }
+               savThread = new SaveThread(engGame);
+               thrSave = new Thread(savThread);
+               thrSave.setName("Save");
+               thrSave.start();
+               ticks = new TickThread(engGame);
+               thrTicks = new Thread(ticks);
+               thrTicks.setName("Ticks");
+               thrTicks.start();
+
+               try {
+                       srvServer = new ServerSocket(engGame.port, 25);
+               } catch (Exception e) {
+                       engGame.log.printError("DuskServer():Creating server socket", e);
+                       engGame.log.printMessage(Log.ALWAYS, "Shutting Down");
+                       System.exit(0);
+               }
+       }
+
+       /**
+        * Accepts incoming connections.
+        */
+       public void run() {
+               LivingThing thnStore = null;
+               while (true) {
+                       try {
+                               sckStore = srvServer.accept();
+                               sckStore.setSoTimeout(30000);
+
+                               thnStore = new LivingThing(sckStore, engGame);
+                               Thread thrLivingThing = new Thread(thnStore);
+                               thrLivingThing.setName("LivingThing(new)");
+                               thrLivingThing.start();
+                       } catch (Exception e) {
+                               engGame.log.printError("DuskServer.run()", e);
+                               engGame.log.printMessage(Log.ALWAYS, "Shutting Down");
+                               System.exit(0);
+                               return;
+                       }
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/Faction.java b/DuskServer/src/duskz/server/Faction.java
new file mode 100644 (file)
index 0000000..b48e814
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+import duskz.server.entity.TileMap.MapData;
+import duskz.server.entity.Mob;
+import duskz.server.entity.LivingThing;
+import duskz.server.entity.DuskObject;
+import java.io.*;
+import java.util.Vector;
+import java.lang.Math;
+
+/**
+ * a Faction represents a group of mobs.
+ *
+ * @author Tom Weingarten
+ */
+public class Faction {
+
+       final public String strName;
+       Vector vctRelations;
+       DuskEngine game;
+       boolean blnHasChanged = false;
+
+       public Faction(String inName, DuskEngine inGame) {
+               strName = inName;
+               game = inGame;
+               vctRelations = new Vector(0);
+               parseFactionData();
+       }
+
+       void parseFactionData() {
+               RandomAccessFile rafFile = null;
+               try {
+                       rafFile = new RandomAccessFile("factions/" + strName, "r");
+                       String strStore = rafFile.readLine();
+                       while (!(strStore == null || strStore.equals("."))) {
+                               if (strStore.equalsIgnoreCase("relation")) {
+                                       vctRelations.addElement(new Relation(rafFile.readLine().toLowerCase(), Double.valueOf(rafFile.readLine()).doubleValue()));
+                               }
+                               strStore = rafFile.readLine();
+                       }
+                       rafFile.close();
+               } catch (Exception e) {
+                       game.log.printError("parseFactionData()", e);
+               }
+       }
+
+       synchronized void saveFactionData() {
+               /*
+                ** Only save faction data if it has changed.
+                */
+               if (!blnHasChanged) {
+                       return;
+               }
+               int i;
+               RandomAccessFile rafFile;
+               try {
+                       rafFile = new RandomAccessFile("factions/" + strName, "rw");
+                       Relation relStore;
+                       for (i = 0; i < vctRelations.size(); i++) {
+                               relStore = (Relation) vctRelations.elementAt(i);
+                               rafFile.writeBytes("relation\n" + relStore.strName.toLowerCase() + "\n" + relStore.dblLevel + "\n");
+                       }
+                       rafFile.writeBytes(".\n");
+                       rafFile.close();
+               } catch (Exception e) {
+                       game.log.printError("saveFactionData()", e);
+               }
+               blnHasChanged = false;
+       }
+
+       double getRelationValue(String strName) {
+               Relation relStore;
+               for (int i = 0; i < vctRelations.size(); i++) {
+                       relStore = (Relation) vctRelations.elementAt(i);
+                       if (strName.equalsIgnoreCase(relStore.strName)) {
+                               if (i > 100) {
+                                       vctRelations.removeElementAt(i);
+                                       vctRelations.insertElementAt(relStore, 0);
+                               }
+                               return relStore.dblLevel;
+                       }
+               }
+               return 0; //if no set relation, impartial
+       }
+
+       Relation getRelation(String strName) {
+               Relation relStore;
+               for (int i = 0; i < vctRelations.size(); i++) {
+                       relStore = (Relation) vctRelations.elementAt(i);
+                       if (strName.equalsIgnoreCase(relStore.strName)) {
+                               if (i > 100) {
+                                       vctRelations.removeElementAt(i);
+                                       vctRelations.insertElementAt(relStore, 0);
+                               }
+                               return relStore;
+                       }
+               }
+               return null;
+       }
+
+       void killedBy(LivingThing thnStore, LivingThing thnAttacker) {
+               if (game.blnAI) {
+                       double dblOldLevel;
+                       Relation relStore = getRelation(thnAttacker.name);
+                       if (relStore == null) {
+                               relStore = new Relation(thnAttacker.name, 0);
+                               vctRelations.addElement(relStore);
+                               dblOldLevel = 2;
+                       } else {
+                               dblOldLevel = relStore.dblLevel;
+                       }
+                       int delta = thnAttacker.getCharacterPoints() - thnStore.getCharacterPoints();
+                       /*      Uses an optimized form of the function:
+                        ((1.03^delta) + (1.03^-delta)) / (2 + (1.03^delta) + (1.03^-delta))
+                        */
+                       if (delta == 0) {
+                               relStore.dblLevel -= (.5) * (1D + relStore.dblLevel);
+                       } else if (delta > 0) {
+                               relStore.dblLevel -= ((((Math.pow(1.03, delta)) / (Math.pow(1.03, delta) + 2))) / 2) * (1 + relStore.dblLevel);
+                       } else {
+                               relStore.dblLevel -= ((Math.pow(1.03, (-1 * delta)) / (Math.pow(1.03, (-1 * delta)) + 2)) / 2) * (1 + relStore.dblLevel);
+                       }
+                       if (!(thnAttacker.clan == null || thnAttacker.clan.equals("none"))) {
+                               relStore = getRelation(thnAttacker.clan);
+                               if (relStore == null) {
+                                       relStore = new Relation(thnAttacker.clan, 0);
+                                       vctRelations.addElement(relStore);
+                               }
+                               if (delta == 0) {
+                                       relStore.dblLevel -= (.5) * (1 + relStore.dblLevel);
+                               } else if (delta > 0) {
+                                       relStore.dblLevel -= ((((Math.pow(1.03, delta)) / (Math.pow(1.03, delta) + 1)) + 1) / 2) * (1 + relStore.dblLevel);
+                               } else {
+                                       relStore.dblLevel -= ((((Math.pow(1.03, (-1 * delta))) / (Math.pow(1.03, (-1 * delta) + 1))) + 1) / 2) * (1 + relStore.dblLevel);
+                               }
+                       }
+                       if (relStore.dblLevel != dblOldLevel) {
+                               blnHasChanged = true;
+                       }
+               }
+       }
+
+       void runAI(Mob mob) {
+               if (!game.blnAI) {
+                       mob.blnCanSeePlayer = false;
+                       return;
+               }
+
+               //Battle AI (inside Battle class)
+               if (mob.battle != null) {
+                       return;
+               }
+
+               // FIXME: can this be moved to DuskEngine somehow?
+
+               //Default AI
+               int intConfidence = 0;
+               LivingThing enemy = null;
+               Mob mobStore;
+               double enemyrelation = 0;
+               boolean visiblePlayer = false;
+               for (MapData md : game.map.range(mob.x, mob.y, game.viewrange - 1)) {
+                       for (DuskObject o : md.entities) {
+                               if (o.isLivingThing()) {
+                                       LivingThing lt = (LivingThing) o;
+                                       boolean visible = game.canSeeLivingThing(mob, lt);
+
+                                       if (visible && game.canSeeTo(mob, lt.x, lt.y)) {
+                                               if (lt.isPlayer()) {
+                                                       visiblePlayer = true;
+                                                       double relation = getRelationValue(lt.name);
+                                                       if (!(lt.clan == null || lt.clan.equals("none"))) {
+                                                               relation = (relation + getRelationValue(lt.clan)) / 2;
+                                                       }
+                                                       if (relation < 0) {
+                                                               if (enemy == null) {
+                                                                       enemy = lt;
+                                                                       enemyrelation = relation;
+                                                               } else {
+                                                                       if (enemyrelation < relation) {
+                                                                               enemy = lt;
+                                                                               enemyrelation = relation;
+                                                                       }
+                                                               }
+                                                       }
+                                                       intConfidence += relation * lt.getTotalPoints();
+                                               }
+                                               if (lt.isMob()) {
+                                                       double relation;
+
+                                                       mobStore = (Mob) lt;
+                                                       if (mobStore.name.equals(mob.name)) {
+                                                               relation = mobStore.dblGroupRelation;
+                                                       } else {
+                                                               relation = getRelationValue(mobStore.name);
+                                                       }
+                                                       intConfidence += relation * mobStore.getTotalPoints();
+                                                       if (relation < 0) {
+                                                               if (enemy == null) {
+                                                                       enemy = mobStore;
+                                                                       enemyrelation = relation;
+                                                               } else {
+                                                                       if (enemyrelation > relation) {
+                                                                               enemy = mobStore;
+                                                                               enemyrelation = relation;
+                                                                       }
+                                                               }
+                                                       }
+                                                       intConfidence += relation * lt.getTotalPoints();
+                                               }
+                                       }
+                               }
+                       }
+               }
+               if (!visiblePlayer) {
+                       mob.blnCanSeePlayer = false;
+                       return;
+               }
+               mob.blnCanSeePlayer = true;
+               if (enemy != null) {
+                       double delta = (mob.getTotalPoints() + intConfidence) * mob.dblBravery * -1 * enemyrelation;
+                       int enemycp = enemy.getTotalPoints();
+                       //Fight/flee
+                       if (enemycp < delta) {
+                               if (enemycp > delta - (delta * 0.1 * Math.random())) {
+                                       return;
+                               }
+                               //Fight
+                               if (enemy.tileDistance(mob) <= mob.getRangeWithBonus()) {
+                                       System.out.println(mob.name + " close enough, going into battle distance: " + enemy.distance(mob) + " range: " + mob.getRangeWithBonus());
+                                       // close enough to attack, so stop moving
+                                       mob.clearMoveQueue();
+                                       game.newBattle(mob, enemy);
+                                       /*
+                                        try {
+                                        // TODO: just call duskEngine.newBattle directly?
+                                        Commands.parseCommand(mob, game, "a " + enemy.name);
+                                        } catch (Exception e) {
+                                        game.log.printError("runAI():" + mob.name + " had an error attacking " + enemy.name, e);
+                                        }*/
+                               } else {
+                                       mob.goTo(enemy.x, enemy.y, false);
+                               }
+                       } else {
+                               if (enemycp < delta + (delta * 0.1 * Math.random())) {
+                                       return;
+                               }
+                               //Flee
+                               int destX;
+                               int destY;
+                               if (enemy.x > mob.x) {
+                                       destX = mob.x - game.viewrange;
+                               } else {
+                                       destX = mob.x + game.viewrange;
+                               }
+                               if (enemy.y > mob.y) {
+                                       destY = mob.y - game.viewrange;
+                               } else {
+                                       destY = mob.y + game.viewrange;
+                               }
+                               mob.goTo(destX, destY, true);
+                       }
+               }
+
+               //If no enemies
+               if ((int) (Math.random() * 25) == 1) {
+                       if ((int) (Math.random() * 2) == 1) {
+                               if ((int) (Math.random() * 2) == 1) {
+                                       mob.moveE();
+                               } else {
+                                       mob.moveW();
+                               }
+                       } else {
+                               if ((int) (Math.random() * 2) == 1) {
+                                       mob.moveS();
+                               } else {
+                                       mob.moveN();
+                               }
+                       }
+               }
+       }
+}
+
+/**
+ * a Relation represents a feeling held by one faction for another faction, a
+ * player, or a clan. The mob AI bases it's decisions around Relations.
+ *
+ * @author Tom Weingarten
+ */
+class Relation {
+
+       String strName;
+       double dblLevel = 0; //-1 to 1
+
+       Relation(String inName, double inLevel) {
+               strName = inName;
+               dblLevel = inLevel;
+       }
+}
diff --git a/DuskServer/src/duskz/server/GiveItem.java b/DuskServer/src/duskz/server/GiveItem.java
new file mode 100644 (file)
index 0000000..976cf11
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+/**
+*GiveItem gives an Item to a LivingThing after they kill a mob.
+*
+*@author Tom Weingarten
+*/
+
+public class GiveItem
+{
+       String strItemName;
+       double dblProbability;
+
+       public GiveItem(String strName, double dblProb)
+       {
+               strItemName = strName;
+               dblProbability = dblProb;
+       }
+}
diff --git a/DuskServer/src/duskz/server/ItemList.java b/DuskServer/src/duskz/server/ItemList.java
new file mode 100644 (file)
index 0000000..0fab2ff
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - attempt at cleanup using modern collections.
+ */
+package duskz.server;
+
+import duskz.server.entity.Item;
+import java.util.HashMap;
+import java.util.LinkedList;
+
+/**
+ * Holds all items, keyed by the item type.
+ */
+public class ItemList extends HashMap<String, LinkedList<Item>> {
+
+       public boolean contains(String strItemName) {
+               return containsKey(strItemName.toLowerCase());
+       }
+
+       public void addElement(Item item) {
+               String key = item.name.toLowerCase();
+               if (contains(key)) {
+                       get(key).push(item);
+               } else {
+                       LinkedList<Item> list = new LinkedList<>();
+                       list.push(item);
+                       put(key, list);
+               }
+       }
+
+       public Item removeElement(String name) {
+               name = name.toLowerCase();
+               LinkedList<Item> list = get(name);
+               if (list != null && !list.isEmpty()) {
+                       Item item = list.pop();
+                       if (list.isEmpty()) {
+                               remove(name);
+                       }
+                       return item;
+               }
+               return null;
+       }
+
+       /*
+        **     This method formats the ItemList for sending to the client
+        **     for display of the player's inventory to the player.
+        */
+       public String print() {
+               StringBuilder invBuffer = new StringBuilder();
+               for (String name : keySet()) {
+                       LinkedList<Item> list = get(name);
+                       Item item = list.element();
+
+                       invBuffer.append("").append((char) 3).append(list.size()).append(" ").append(item.name).append("\n");
+               }
+               return invBuffer.toString();
+       }
+
+       /*
+        **     This method formats the ItemList for saving.
+        **     It generates a String that can later be passed
+        **     to fromString for populating a new ItemList.
+        */
+       public String toString() {
+               StringBuilder invBuffer = new StringBuilder();
+               for (String name : keySet()) {
+                       LinkedList<Item> list = get(name);
+
+                       for (Item item : list) {
+                               invBuffer.append(item.toString()).append("/\n");
+                       }
+               }
+               return invBuffer.toString();
+       }
+}
diff --git a/DuskServer/src/duskz/server/Log.java b/DuskServer/src/duskz/server/Log.java
new file mode 100644 (file)
index 0000000..4d3f89f
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+import java.io.PrintStream;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+
+public class Log
+{
+    public static final int ALWAYS = 0;
+    public static final int INFO = 1;
+    public static final int ERROR = 2;
+    public static final int VERBOSE = 3;
+    public static final int DEBUG = 4;
+
+    
+       private static final String MSG_ALWAYS = "ALWAYS";
+       private static final String MSG_INFO = "INFO";
+       private static final String MSG_ERROR = "ERROR";
+       private static final String MSG_VERBOSE = "VERBOSE";
+       private static final String MSG_DEBUG = "DEBUG";
+       private static final String LOG_SEP = "::";
+       private PrintStream psOut;
+    private int logLevel = ERROR;
+       private SimpleDateFormat formatter;
+
+       public Log(PrintStream ps)
+       {
+               formatter = new SimpleDateFormat("EEE MMM dd hh:mm:ss yyyy", Locale.getDefault());
+               if (ps != null)
+               {
+                       psOut = ps;
+               } else
+               {
+                       psOut = System.out;
+               }
+       }
+
+    public void setLogLevel(int newLogLevel)
+       {
+        if ((newLogLevel >= ALWAYS) && (newLogLevel <= DEBUG))
+               {
+            logLevel = newLogLevel;
+        }
+    }
+
+    public int getLogLevel()
+       {
+        return logLevel;
+    }
+
+       private void printTimeStamp(int level)
+       {
+               switch(level)
+               {
+                       case ALWAYS:
+                       {
+                               psOut.print(MSG_ALWAYS+LOG_SEP);
+                               break;
+                       }
+                       case ERROR:
+                       {
+                               psOut.print(MSG_ERROR+LOG_SEP);
+                               break;
+                       }
+                       case INFO:
+                       {
+                               psOut.print(MSG_INFO+LOG_SEP);
+                               break;
+                       }
+                       case VERBOSE:
+                       {
+                               psOut.print(MSG_VERBOSE+LOG_SEP);
+                               break;
+                       }
+                       case DEBUG:
+                       {
+                               psOut.print(MSG_DEBUG+LOG_SEP);
+                               break;
+                       }
+               }
+               psOut.print(formatter.format(new Date())+LOG_SEP);
+               if (logLevel >= DEBUG)
+               {
+                       psOut.print("thread="+Thread.currentThread().getName()+LOG_SEP);
+               }
+       }
+
+       public void printMessage(int level, String strMessage)
+       {
+        if (level <= logLevel)
+               {
+                       printTimeStamp(level);
+                       psOut.println(strMessage);
+               }
+       }
+
+       public void printError(String strMessage, Exception e)
+       {
+        if (logLevel >= ERROR)
+               {
+                       printTimeStamp(ERROR);
+                       psOut.print(strMessage+LOG_SEP);
+                       if (logLevel >= DEBUG)
+                       {
+                               e.printStackTrace(psOut);
+                       } else
+                       {
+                               psOut.println(e.toString());
+                       }
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/RandomAccessString.java b/DuskServer/src/duskz/server/RandomAccessString.java
new file mode 100644 (file)
index 0000000..e91fd07
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+package duskz.server;
+
+import java.io.*;
+
+// TODO: wont be needed with javascript
+@Deprecated
+public class  RandomAccessString
+{
+       private String strContent = null;
+       private String strCurrentContent = null;
+       private int lCurrentPosition;
+
+       public RandomAccessString(String strFileName)
+       throws IOException
+       {
+               lCurrentPosition = -1;
+               File filView = new File(strFileName);
+               RandomAccessFile rafFile = new RandomAccessFile(filView, "r");
+               byte [] buffer = new byte[(int)rafFile.length()];
+               rafFile.readFully(buffer);
+               rafFile.close();
+               strContent = new String(buffer);
+               strCurrentContent = strContent;
+               lCurrentPosition = 0;
+       }
+
+       public void close()
+       {
+               strContent = null;
+               strCurrentContent = null;
+       }
+
+       public int getFilePointer()
+       {
+               return lCurrentPosition;
+       }
+
+       public void seek(int lSeekPosition)
+       {
+               if (lSeekPosition >= 0 && lSeekPosition < strContent.length())
+               {
+                       lCurrentPosition = lSeekPosition;
+                       strCurrentContent = strContent.substring(lCurrentPosition);
+               }
+       }
+
+       public String readLine()
+       {
+               if (lCurrentPosition == -1 || strCurrentContent == null)
+               {
+                       return null;
+               }
+               String strReturn;
+               int newline = strCurrentContent.indexOf("\r");
+               if (newline == -1)
+               {
+                       newline = strCurrentContent.indexOf("\n");
+                       if (newline == -1)
+                       {
+                               strReturn = strCurrentContent;
+                               strCurrentContent = null;
+                               lCurrentPosition = -1;
+                               return strReturn;
+                       }
+               }
+               strReturn = strCurrentContent.substring(0, newline);
+               while((newline < strCurrentContent.length())
+                         && ((strCurrentContent.charAt(newline) == '\r')
+                         || (strCurrentContent.charAt(newline) == '\n')))
+               {
+                       newline++;
+               }
+               lCurrentPosition += newline;
+               strCurrentContent = strCurrentContent.substring(newline);
+               return strReturn;
+       }
+
+       public byte readByte()
+       throws IOException
+       {
+               if (lCurrentPosition == -1)
+               {
+                       throw new IOException();
+               }
+               byte bReturn = (byte)strContent.charAt(lCurrentPosition);
+               lCurrentPosition++;
+               strCurrentContent = strContent.substring(lCurrentPosition);
+               return bReturn;
+       }
+}
diff --git a/DuskServer/src/duskz/server/SaveThread.java b/DuskServer/src/duskz/server/SaveThread.java
new file mode 100644 (file)
index 0000000..328a238
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+public class SaveThread implements Runnable {
+
+       DuskEngine engGame;
+
+       SaveThread(DuskEngine inGame) {
+               engGame = inGame;
+       }
+
+       public void run() {
+               while (true) {
+                       try {
+                               Thread.currentThread().sleep(3600000);          // sleep for an hour
+                               engGame.saveMap();                      // save the game
+
+                               // Clear out the auto banned IP addresses once an hour
+                               engGame.clearBanned();
+
+                       } catch (Exception e) {
+                               engGame.log.printError("SaveThread.run()", e);
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/Script.java b/DuskServer/src/duskz/server/Script.java
new file mode 100644 (file)
index 0000000..7e9dc6e
--- /dev/null
@@ -0,0 +1,2011 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+package duskz.server;
+
+/*
+ Portions of code relating to getString() and script
+ parameters by Randall Leeds and Tom Weingarten
+ */
+import duskz.server.entity.Mob;
+import duskz.server.entity.LivingThing;
+import duskz.server.entity.Item;
+import duskz.server.entity.DuskObject;
+import java.io.*;
+import java.util.Vector;
+import java.lang.Math;
+import java.util.List;
+
+/**
+ * Script reads and executes DuskScripts.
+ *
+ * @deprecated is to be replaced by JavaScript
+ * @author Tom Weingarten
+ */
+@Deprecated
+public class Script {
+
+       Vector vctUpdate;
+       Vector vctVisibleUpdate;
+       public VariableSet varVariables;
+//     RandomAccessFile rafScript;
+       RandomAccessString rafScript;
+       DuskEngine engGame;
+       String strRead = null;
+       //for script debugging purposes:
+       String strName;
+       int intLine = 0;
+//     long lngQuoteFilePointer;
+       int lngQuoteFilePointer;
+
+       public Script(String strIn, DuskEngine inEngine, boolean forcecompile)
+                       throws Exception {
+               engGame = inEngine;
+               strName = strIn;
+               if (forcecompile) {
+                       File filDelete = new File(strIn + ".dsko");
+                       if (filDelete.exists()) {
+                               filDelete.delete();
+                       }
+                       compileScript(strIn);
+               } else {
+                       File filCompileCheck = new File(strIn + ".dsko");
+                       if (!filCompileCheck.exists()) {
+                               compileScript(strIn);
+                       }
+               }
+               varVariables = new VariableSet();
+//             rafScript = new RandomAccessFile(strIn+".dsko","r");
+               rafScript = new RandomAccessString(strIn + ".dsko");
+               intLine = 0;
+       }
+
+       /**
+        * Helper to run a script with only a trigger arg.
+        *
+        * Silently ignores missing scripts.
+        *
+        * @param name
+        * @param trigger
+        */
+       public static void exec(String name, DuskEngine engGame, LivingThing trigger) {
+               File file = new File(name);
+
+               if (!file.exists())
+                       return;
+
+               Script script = null;
+
+               try {
+                       script = new Script(name, engGame, false);
+                       script.varVariables.addVariable("trigger", trigger);
+                       script.runScript();
+               } catch (Exception e) {
+                       engGame.log.printError("Executing script " + name, e);
+               } finally {
+                       if (script != null) {
+                               try {
+                                       script.close();
+                               } catch (Exception e) {
+                               }
+                       }
+               }
+       }
+       // TODO: work out what i want here/clean up every caller
+
+       public static void exec(String name, DuskEngine engGame) {
+               File file = new File(name);
+
+               if (!file.exists())
+                       return;
+
+               Script script = null;
+
+               try {
+                       script = new Script(name, engGame, false);
+                       script.runScript();
+               } catch (Exception e) {
+                       engGame.log.printError("Executing script " + name, e);
+               } finally {
+                       if (script != null) {
+                               try {
+                                       script.close();
+                               } catch (Exception e) {
+                               }
+                       }
+               }
+       }
+
+       synchronized void compileScript(String name)
+                       throws Exception {
+               RandomAccessFile rafCompile;
+//             rafScript = new RandomAccessFile(name, "r");
+               rafScript = new RandomAccessString(name);
+               try {
+                       rafCompile = new RandomAccessFile(name + ".dsko", "rw");
+               } catch (Exception e) {
+                       engGame.log.printError("compileScript():Opening " + name + ".dsko file for script " + name, e);
+                       return;
+               }
+               try {
+                       while (parseScriptForCompile(rafCompile)) {
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("compileScript():While running parseScriptForCompile() for script " + name, e);
+               }
+               try {
+                       rafCompile.close();
+               } catch (Exception e) {
+                       engGame.log.printError("compileScript():While closing .dsko file for script " + name, e);
+               }
+       }
+
+       public void close() {
+               try {
+                       rafScript.close();
+               } catch (Exception e) {
+                       engGame.log.printError("Script.close():Closing script " + strName, e);
+               }
+       }
+
+       LivingThing getLivingThing(String strName) {
+               try {
+                       LivingThing thnStore;
+                       if (strName.equalsIgnoreCase("player")) {
+                               return engGame.getPlayer(getString());
+                       } else if (strName.equalsIgnoreCase("local")) {
+                               DuskObject objStore = getLivingThing(getString()).getLocalObject(getString());
+                               if (objStore != null && objStore.isLivingThing()) {
+                                       return ((LivingThing) objStore);
+                               }
+                               return null;
+                       } else if (strName.equalsIgnoreCase("enemy")) {
+                               thnStore = getLivingThing(getString());
+                               return Battle.getEnemy(thnStore);
+                       } else if (strName.equalsIgnoreCase("pet")) {
+                               thnStore = getLivingThing(getString());
+                               if (thnStore.getFollowing() != null && thnStore.getFollowing().isPet()) {
+                                       return thnStore.getFollowing();
+                               }
+                               return null;
+                       } else if (strName.equalsIgnoreCase("following")) {
+                               thnStore = getLivingThing(getString());
+                               if (thnStore.getFollowing() != null && thnStore.getFollowing().isPet()) {
+                                       return thnStore.getFollowing();
+                               } else {
+                                       return null;
+                               }
+                       } else if (strName.equalsIgnoreCase("global")) {
+                               Variable varStore = engGame.varVariables.getVariable(readScriptForCompile());
+                               if (varStore != null && varStore.isLivingThing()) {
+                                       return (LivingThing) varStore.objData;
+                               }
+                       }
+                       Variable varStore = varVariables.getVariable(strName);
+                       if (varStore != null && varStore.isLivingThing()) {
+                               return (LivingThing) varStore.objData;
+                       }
+                       thnStore = engGame.getPlayer(strName);
+                       if (thnStore != null) {
+                               return thnStore;
+                       }
+                       thnStore = engGame.getMobFromVct(strName);
+                       if (thnStore != null) {
+                               return thnStore;
+                       }
+                       thnStore = engGame.getPet(strName);
+                       if (thnStore != null) {
+                               return thnStore;
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("getLivingThing()", e);
+               }
+               return null;
+       }
+
+       Double getNumber(String strName) {
+               try {
+                       return Double.valueOf(strName);
+               } catch (NumberFormatException e) {
+               }
+               if (strName.equalsIgnoreCase("global")) {
+                       try {
+                               Variable varStore = engGame.varVariables.getVariable(readScriptForCompile());
+                               if (varStore != null && varStore.isNumber()) {
+                                       return (Double) varStore.objData;
+                               }
+                       } catch (Exception e) {
+                               return null;
+                       }
+               }
+               Variable varStore = varVariables.getVariable(strName);
+               if (varStore != null && varStore.isNumber()) {
+                       return (Double) varStore.objData;
+               }
+               return null;
+       }
+
+       private void rewindScript() {
+               intLine = 0;
+               strRead = null;
+               try {
+                       rafScript.seek(0);
+               } catch (Exception e) {
+                       engGame.log.printError("rewindScript()", e);
+               }
+       }
+
+       public void runScript() {
+               rewindScript();
+               vctUpdate = new Vector(0);
+               vctVisibleUpdate = new Vector(0);
+               while (parseScript()) {
+               }
+               LivingThing thnStore;
+               for (int i = 0; i < vctUpdate.size(); i++) {
+                       thnStore = (LivingThing) vctUpdate.elementAt(i);
+                       thnStore.updateStats();
+               }
+               for (int i = 0; i < vctVisibleUpdate.size(); i++) {
+                       thnStore = (LivingThing) vctVisibleUpdate.elementAt(i);
+                       engGame.removeDuskObject(thnStore);
+                       engGame.addDuskObject(thnStore);
+               }
+       }
+
+       public void runScript(String strParams) {
+               String strStore2;
+               int i2;
+               try {
+                       for (int i = 0; !strParams.equals(""); i++) {
+                               if (strParams.startsWith("\"")) {
+                                       char c, c2;
+
+                                       strStore2 = "";
+                                       i2 = 1;
+                                       while (true) {
+                                               c = strParams.charAt(i2);
+                                               if (c == '\\') {
+                                                       c2 = strParams.charAt(i2 + 1);
+                                                       strStore2 += c2;
+                                               } else if (c == '\"') {
+                                                       i2++;
+                                                       break;
+                                               } else {
+                                                       strStore2 += c;
+                                               }
+                                               i2++;
+                                       }
+                               } else {
+                                       i2 = strParams.indexOf(" ");
+                                       if (i2 == -1) {
+                                               strStore2 = strParams;
+                                               varVariables.addVariable("param" + i, strStore2);
+                                               break;
+                                       } else {
+                                               strStore2 = strParams.substring(0, i2);
+                                       }
+                               }
+                               varVariables.addVariable("param" + i, strStore2);
+                               if (strParams.length() > i2) {
+                                       strParams = strParams.substring(i2 + 1);
+                               } else {
+                                       strParams = "";
+                               }
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("runScript()", e);
+               }
+               runScript();
+       }
+
+       public boolean rewindAndParseScript() {
+               rewindScript();
+               return parseScript();
+       }
+
+       String readScriptForCompile()
+                       throws IOException {
+               String strStore2;
+               if (strRead == null) {
+                       // initialize quotation marker before read as we do not know whether
+                       // readLine is stripping a cr or a cr/lf pair.  This eliminates the
+                       // need to use strRead.length() in the calculation.
+                       lngQuoteFilePointer = rafScript.getFilePointer();
+                       strRead = rafScript.readLine();
+                       if (strRead == null) {
+                               return null;
+                       }
+                       // Scan for quotation marks before we can clean up the string with trim
+                       int q = strRead.indexOf("\"");
+                       if (q != -1) {
+                               lngQuoteFilePointer += q + 1;
+                       }
+                       strRead = strRead.trim();
+                       intLine++;
+               }
+               int i = strRead.indexOf(" ");
+               if (i == -1) {
+                       strStore2 = strRead;
+                       strRead = null;
+                       return strStore2;
+               }
+               strStore2 = strRead.substring(0, i).trim();
+               try {
+                       strRead = strRead.substring(i + 1, strRead.length());
+               } catch (Exception e) {
+                       strRead = null;
+               }
+               return strStore2;
+       }
+
+       String getStringForCompile()
+                       throws IOException {
+               String strStore;
+               strStore = readScriptForCompile();
+
+               if (strStore.equals("concat")) {
+                       return "concat " + getStringForCompile() + getStringForCompile();
+               }
+
+               if (strStore.equalsIgnoreCase("name")) {
+                       return "name " + getStringForCompile();
+               }
+
+               if (strStore.equalsIgnoreCase("enemy")) {
+                       return "enemy " + getStringForCompile();
+               }
+
+               if (strStore.equalsIgnoreCase("following")) {
+                       return "following " + getStringForCompile();
+               }
+
+               if (strStore.equalsIgnoreCase("clan")) {
+                       return "clan " + getStringForCompile();
+               }
+
+               if (strStore.startsWith("\"")) {
+                       char c, c2;
+                       //Go back to the beginning of the quote
+                       rafScript.seek(lngQuoteFilePointer);
+
+                       //Read quote into strStore2
+                       strStore = "\"";
+                       while (true) {
+                               c = (char) rafScript.readByte();
+                               if (c == '\\') {
+                                       c2 = (char) rafScript.readByte();
+                                       strStore += "\\";
+                                       strStore += c2;
+                               } else if (c == '\"') {
+                                       break;
+                               } else if (c == '\n') {
+                                       strStore += "\n";
+                                       intLine++;
+                               } else if (c == '\r') {
+                                       strStore += "\n";
+                                       intLine++;
+                                       // Skip over LF as this was a CR/LF pair
+                                       c2 = (char) rafScript.readByte();
+                                       if (c2 != '\n') {
+                                               // Back up 1 char if this wasn't a CR/LF pair
+                                               rafScript.seek(rafScript.getFilePointer() - 1);
+                                       }
+                               } else //If no special characters exist, add it to the string
+                               {
+                                       strStore += c;
+                               }
+                       }
+                       strRead = null; //Delete strRead, readScriptForCompile will recreate it
+                       strStore += "\"";
+                       return strStore;
+               } else {
+                       if (strStore.equalsIgnoreCase("global")) {
+                               strStore = getStringForCompile();
+                               return "global " + strStore;
+                       }
+               }
+               return strStore + " ";
+       }
+
+       String readScript()
+                       throws IOException {
+               String strStore = "";
+               char c = (char) rafScript.readByte();
+               while (c != ' ') {
+                       strStore += c;
+                       c = (char) rafScript.readByte();
+               }
+               return strStore;
+       }
+
+       String getString()
+                       throws IOException {
+               String strStore = "";
+//             long lngOldFilePointer;
+               int lngOldFilePointer;
+
+               lngOldFilePointer = rafScript.getFilePointer();
+
+               char c = (char) rafScript.readByte();
+
+               //Skip over leading spaces
+               while (c == ' ') {
+                       lngOldFilePointer++;
+                       c = (char) rafScript.readByte();
+               }
+
+               if (c == '\"') {
+                       c = (char) rafScript.readByte();
+                       while (c != '\"') {
+                               strStore += c;
+                               c = (char) rafScript.readByte();
+                       }
+               } else {
+                       while (c != ' ') {
+                               strStore += c;
+                               c = (char) rafScript.readByte();
+                       }
+               }
+
+               if (strStore.equals("concat")) {
+                       return getString() + getString();
+               }
+
+               if (strStore.equalsIgnoreCase("name")) {
+                       LivingThing thnStore = getLivingThing(getString());
+                       if (thnStore != null) {
+                               return thnStore.name;
+                       }
+                       return "name";
+               }
+
+               if (strStore.equalsIgnoreCase("clan")) {
+                       LivingThing thnStore = getLivingThing(getString());
+                       if (thnStore != null) {
+                               return thnStore.clan;
+                       }
+                       return "clan";
+               }
+
+               if (strStore.startsWith("\"")) {
+                       char c2;
+                       //Go back to the beginning of the quote
+                       rafScript.seek(lngOldFilePointer + 1);
+
+                       //Read quote into strStore2
+                       strStore = "";
+                       while (true) {
+                               c = (char) rafScript.readByte();
+                               if (c == '\\') {
+                                       c2 = (char) rafScript.readByte();
+                                       strStore += c2;
+                               } else if (c == '\"') {
+                                       break;
+                               } else //If no special characters exist, add it to the string
+                               {
+                                       strStore += c;
+                               }
+                       }
+//                     try
+//                     {
+//                             rafScript.seek(rafScript.getFilePointer()+1);// Why do I need this to skip over ending quote?
+//                     }catch(EOFException e){}
+               } else {
+                       Variable varStore = null;
+                       if (strStore.equalsIgnoreCase("global")) {
+                               strStore = getString();
+                               varStore = engGame.varVariables.getVariable(strStore);
+                       } else {
+                               varStore = varVariables.getVariable(strStore);
+                       }
+                       if (varStore == null) {
+                               return strStore;
+                       } else if (varStore.isString()) {
+                               return (String) varStore.objData;
+                       } else if (varStore.isLivingThing()) {
+                               return strStore;
+                       } else if (varStore.isNumber()) {
+                               return String.valueOf(((Double) varStore.objData).intValue());
+                       }
+               }
+               return strStore;
+       }
+
+       boolean parseScriptForCompile(RandomAccessFile rafCompile)
+                       throws Exception {
+               String strStore;
+               try {
+                       strStore = readScriptForCompile();
+                       if (strStore == null) {
+                               return false;
+                       }
+               } catch (EOFException e) {
+                       return false;
+               }
+               if (strStore.startsWith("#") || strStore.equals(" ")) //comments
+               {
+                       strRead = null;
+                       intLine++;
+                       return true;
+               }
+               if (strStore.equals("!") || strStore.equalsIgnoreCase("not")) //Not, returns the opposite of the next line
+               {
+                       rafCompile.writeByte(0);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("if")) {
+                       rafCompile.writeByte(1);
+                       return true;
+               } else if (strStore.equals("end")) {
+                       rafCompile.writeByte(2);
+                       return true;
+               } else if (strStore.equals(")") || strStore.equals("(")) {
+                       return true;
+               } else if (strStore.equalsIgnoreCase("t") || strStore.equalsIgnoreCase("true")) {
+                       rafCompile.writeByte(3);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("f") || strStore.equalsIgnoreCase("false")) {
+                       rafCompile.writeByte(4);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("playsound")) {
+                       rafCompile.writeByte(5);
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("order")) {
+                       rafCompile.writeByte(6);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("hascondition")) {
+                       rafCompile.writeByte(7);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("addcondition")) {
+                       rafCompile.writeByte(8);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("addconditionwithduration")) {
+                       rafCompile.writeByte(9);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("removecondition")) {
+                       rafCompile.writeByte(10);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("addflag")) {
+                       rafCompile.writeByte(11);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("hasflag")) {
+                       rafCompile.writeByte(12);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("removeflag")) {
+                       rafCompile.writeByte(13);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("global")) {
+                       strStore = getStringForCompile().trim();
+                       if (strStore.equalsIgnoreCase("livingthing")) {
+                               rafCompile.writeByte(14);
+                               rafCompile.writeBytes(readScriptForCompile() + " ");
+                               rafCompile.writeBytes(getStringForCompile());
+                               return true;
+                       } else if (strStore.equalsIgnoreCase("number")) {
+                               rafCompile.writeByte(15);
+                               rafCompile.writeBytes(readScriptForCompile() + " ");
+                               rafCompile.writeBytes(parseValueForCompile());
+                               return true;
+                       } else if (strStore.equalsIgnoreCase("string")) {
+                               rafCompile.writeByte(16);
+                               rafCompile.writeBytes(readScriptForCompile() + " ");
+                               rafCompile.writeBytes(getStringForCompile());
+                               return true;
+                       }
+               } else if (strStore.equalsIgnoreCase("livingthing")) {
+                       rafCompile.writeByte(17);
+                       rafCompile.writeBytes(readScriptForCompile() + " ");
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("number")) {
+                       rafCompile.writeByte(18);
+                       rafCompile.writeBytes(readScriptForCompile() + " ");
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("string")) {
+                       rafCompile.writeByte(19);
+                       rafCompile.writeBytes(readScriptForCompile() + " ");
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("or")) {
+                       rafCompile.writeByte(20);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("and")) {
+                       rafCompile.writeByte(21);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("<")) {
+                       rafCompile.writeByte(22);
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase(">")) {
+                       rafCompile.writeByte(23);
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("=")) {
+                       rafCompile.writeByte(24);
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("isinbattle")) {
+                       rafCompile.writeByte(25);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("isclan")) {
+                       rafCompile.writeByte(26);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("israce")) {
+                       rafCompile.writeByte(27);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("hasitem")) {
+                       rafCompile.writeByte(28);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("createmob")) {
+                       rafCompile.writeByte(29);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("createoneusemob")) {
+                       rafCompile.writeByte(30);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("createitem")) {
+                       rafCompile.writeByte(31);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("giveitem")) {
+                       rafCompile.writeByte(59);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("removeitem")) {
+                       rafCompile.writeByte(33);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("iswearing")) {
+                       rafCompile.writeByte(34);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("unwear")) {
+                       rafCompile.writeByte(35);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("variableisnumber")) {
+                       rafCompile.writeByte(36);
+                       strStore = getStringForCompile();
+                       if (strStore.equalsIgnoreCase("global")) {
+                               rafCompile.writeBytes("global ");
+                               strStore = getStringForCompile();
+                       }
+                       rafCompile.writeBytes(strStore);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("variableisstring")) {
+                       rafCompile.writeByte(37);
+                       strStore = getStringForCompile();
+                       if (strStore.equalsIgnoreCase("global")) {
+                               rafCompile.writeBytes("global ");
+                               strStore = getStringForCompile();
+                       }
+                       rafCompile.writeBytes(strStore);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("variableislivingthing")) {
+                       rafCompile.writeByte(38);
+                       strStore = getStringForCompile();
+                       if (strStore.equalsIgnoreCase("global")) {
+                               rafCompile.writeBytes("global ");
+                               strStore = getStringForCompile();
+                       }
+                       rafCompile.writeBytes(strStore);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("isplayer")) {
+                       rafCompile.writeByte(39);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("ispet")) {
+                       rafCompile.writeByte(40);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("ismob")) {
+                       rafCompile.writeByte(41);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("chat")) {
+                       rafCompile.writeByte(42);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("chatc")) {
+                       rafCompile.writeByte(43);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("inc")) {
+                       rafCompile.writeByte(44);
+                       rafCompile.writeBytes(getStringForCompile());
+                       strStore = readScriptForCompile();
+                       if (strStore.equalsIgnoreCase("hp")) {
+                               rafCompile.writeByte(0);
+                       }
+                       if (strStore.equalsIgnoreCase("maxhp")) {
+                               rafCompile.writeByte(1);
+                       }
+                       if (strStore.equalsIgnoreCase("hpbonus")) {
+                               rafCompile.writeByte(2);
+                       }
+                       if (strStore.equalsIgnoreCase("mp")) {
+                               rafCompile.writeByte(3);
+                       }
+                       if (strStore.equalsIgnoreCase("maxmp")) {
+                               rafCompile.writeByte(4);
+                       }
+                       if (strStore.equalsIgnoreCase("mpbonus")) {
+                               rafCompile.writeByte(5);
+                       }
+                       if (strStore.equalsIgnoreCase("damdone")) {
+                               rafCompile.writeByte(6);
+                       }
+                       if (strStore.equalsIgnoreCase("strength")) {
+                               rafCompile.writeByte(7);
+                       }
+                       if (strStore.equalsIgnoreCase("intelligence")) {
+                               rafCompile.writeByte(8);
+                       }
+                       if (strStore.equalsIgnoreCase("dexterity")) {
+                               rafCompile.writeByte(9);
+                       }
+                       if (strStore.equalsIgnoreCase("wisdom")) {
+                               rafCompile.writeByte(10);
+                       }
+                       if (strStore.equalsIgnoreCase("constitution")) {
+                               rafCompile.writeByte(11);
+                       }
+                       if (strStore.equalsIgnoreCase("strengthbonus")) {
+                               rafCompile.writeByte(12);
+                       }
+                       if (strStore.equalsIgnoreCase("intelligencebonus")) {
+                               rafCompile.writeByte(13);
+                       }
+                       if (strStore.equalsIgnoreCase("dexteritybonus")) {
+                               rafCompile.writeByte(14);
+                       }
+                       if (strStore.equalsIgnoreCase("wisdombonus")) {
+                               rafCompile.writeByte(15);
+                       }
+                       if (strStore.equalsIgnoreCase("constitutionbonus")) {
+                               rafCompile.writeByte(16);
+                       }
+                       if (strStore.equalsIgnoreCase("acbonus")) {
+                               rafCompile.writeByte(17);
+                       }
+                       if (strStore.equalsIgnoreCase("dammodbonus")) {
+                               rafCompile.writeByte(18);
+                       }
+                       if (strStore.equalsIgnoreCase("locx")) {
+                               rafCompile.writeByte(19);
+                       }
+                       if (strStore.equalsIgnoreCase("locy")) {
+                               rafCompile.writeByte(20);
+                       }
+                       if (strStore.equalsIgnoreCase("locxy")) {
+                               rafCompile.writeByte(21);
+                               rafCompile.writeBytes(parseValueForCompile());
+                       }
+                       if (strStore.equalsIgnoreCase("exp")) {
+                               rafCompile.writeByte(22);
+                       }
+                       if (strStore.equalsIgnoreCase("cash")) {
+                               rafCompile.writeByte(23);
+                       }
+                       if (strStore.equalsIgnoreCase("skill")) {
+                               rafCompile.writeByte(24);
+                               rafCompile.writeBytes(getStringForCompile());
+                       }
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("set")) {
+                       rafCompile.writeByte(45);
+                       rafCompile.writeBytes(getStringForCompile());
+                       strStore = readScriptForCompile();
+                       if (strStore.equalsIgnoreCase("hp")) {
+                               rafCompile.writeByte(0);
+                       }
+                       if (strStore.equalsIgnoreCase("maxhp")) {
+                               rafCompile.writeByte(1);
+                       }
+                       if (strStore.equalsIgnoreCase("hpbonus")) {
+                               rafCompile.writeByte(2);
+                       }
+                       if (strStore.equalsIgnoreCase("mp")) {
+                               rafCompile.writeByte(3);
+                       }
+                       if (strStore.equalsIgnoreCase("maxmp")) {
+                               rafCompile.writeByte(4);
+                       }
+                       if (strStore.equalsIgnoreCase("mpbonus")) {
+                               rafCompile.writeByte(5);
+                       }
+                       if (strStore.equalsIgnoreCase("damdone")) {
+                               rafCompile.writeByte(6);
+                       }
+                       if (strStore.equalsIgnoreCase("strength")) {
+                               rafCompile.writeByte(7);
+                       }
+                       if (strStore.equalsIgnoreCase("intelligence")) {
+                               rafCompile.writeByte(8);
+                       }
+                       if (strStore.equalsIgnoreCase("dexterity")) {
+                               rafCompile.writeByte(9);
+                       }
+                       if (strStore.equalsIgnoreCase("wisdom")) {
+                               rafCompile.writeByte(10);
+                       }
+                       if (strStore.equalsIgnoreCase("constitution")) {
+                               rafCompile.writeByte(11);
+                       }
+                       if (strStore.equalsIgnoreCase("strengthbonus")) {
+                               rafCompile.writeByte(12);
+                       }
+                       if (strStore.equalsIgnoreCase("intelligencebonus")) {
+                               rafCompile.writeByte(13);
+                       }
+                       if (strStore.equalsIgnoreCase("dexteritybonus")) {
+                               rafCompile.writeByte(14);
+                       }
+                       if (strStore.equalsIgnoreCase("wisdombonus")) {
+                               rafCompile.writeByte(15);
+                       }
+                       if (strStore.equalsIgnoreCase("constitutionbonus")) {
+                               rafCompile.writeByte(16);
+                       }
+                       if (strStore.equalsIgnoreCase("acbonus")) {
+                               rafCompile.writeByte(17);
+                       }
+                       if (strStore.equalsIgnoreCase("dammodbonus")) {
+                               rafCompile.writeByte(18);
+                       }
+                       if (strStore.equalsIgnoreCase("locx")) {
+                               rafCompile.writeByte(19);
+                       }
+                       if (strStore.equalsIgnoreCase("locy")) {
+                               rafCompile.writeByte(20);
+                       }
+                       if (strStore.equalsIgnoreCase("locxy")) {
+                               rafCompile.writeByte(21);
+                               rafCompile.writeBytes(parseValueForCompile());
+                       }
+                       if (strStore.equalsIgnoreCase("exp")) {
+                               rafCompile.writeByte(22);
+                       }
+                       if (strStore.equalsIgnoreCase("cash")) {
+                               rafCompile.writeByte(23);
+                       }
+                       if (strStore.equalsIgnoreCase("skill")) {
+                               rafCompile.writeByte(24);
+                               rafCompile.writeBytes(getStringForCompile());
+                       }
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("changeTile")) {
+                       rafCompile.writeByte(46);
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       rafCompile.writeBytes(parseValueForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("strequals")) {
+                       rafCompile.writeByte(47);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("input")) {
+                       rafCompile.writeByte(48);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("checkviewable")) {
+                       rafCompile.writeByte(49);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("log")) {
+                       rafCompile.writeByte(50);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("gecho")) {
+                       rafCompile.writeByte(51);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("endscript")) {
+                       rafCompile.writeByte(4);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("chatwindow")) {
+                       rafCompile.writeByte(52);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("kill")) {
+                       rafCompile.writeByte(53);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("endcommand")) {
+                       rafCompile.writeByte(54);
+                       return true;
+               } else if (strStore.equalsIgnoreCase("clanleader")) {
+                       rafCompile.writeByte(55);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("changeclan")) {
+                       rafCompile.writeByte(56);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("floodoff")) {
+                       rafCompile.writeByte(57);
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               } else if (strStore.equalsIgnoreCase("battlechat")) {
+                       rafCompile.writeByte(58);
+                       rafCompile.writeBytes(getStringForCompile());
+                       rafCompile.writeBytes(getStringForCompile());
+                       return true;
+               }
+               rafCompile.writeBytes(strStore + " ");
+               return true;
+       }
+
+       boolean parseScript() {
+               intLine++;
+               byte bytCommand = 0;
+               try {
+                       bytCommand = rafScript.readByte();
+                       // Skip over spaces between commands (if any)
+                       while (bytCommand == 32) {
+                               bytCommand = rafScript.readByte();
+                       }
+                       switch (bytCommand) {
+                               case 0: {
+                                       if (parseScript()) {
+                                               return false;
+                                       }
+                                       return true;
+                               }
+                               case 1: {
+                                       if (!parseScript()) {
+                                               int ifCount = 1;
+                                               byte bytStore;
+                                               while (true) {
+                                                       bytStore = rafScript.readByte();
+                                                       if (bytStore == 1) {
+                                                               ifCount++;
+                                                       } else if (bytStore == 2) {
+                                                               ifCount--;
+                                                               if (ifCount == 0) {
+                                                                       break;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       return true;
+                               }
+                               case 2: {
+                                       return true;
+                               }
+                               case 3: {
+                                       return true;
+                               }
+                               case 4: {
+                                       return false;
+                               }
+                               case 5: {
+                                       engGame.playSound((int) parseValue(), (int) parseValue(), (int) parseValue());
+                                       return true;
+                               }
+                               case 6: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       Commands.parseCommand(thnStore, engGame, getString());
+                                       return true;
+                               }
+                               case 7: {
+                                       return getLivingThing(getString()).hasCondition(getString());
+                               }
+                               case 8: {
+                                       getLivingThing(getString()).addCondition(engGame.getCondition(getString()));
+                                       return true;
+                               }
+                               case 9: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       Condition cndStore = engGame.getCondition(getString());
+                                       cndStore.duration = (int) parseValue();
+                                       thnStore.addCondition(cndStore);
+                                       return true;
+                               }
+                               case 10: {
+                                       getLivingThing(getString()).removeCondition(getString());
+                                       return true;
+                               }
+                               case 11: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       thnStore.flags.add(getString());
+                                       if (vctVisibleUpdate != null || vctVisibleUpdate.contains(thnStore)) {
+                                               vctVisibleUpdate.addElement(thnStore);
+                                       }
+                                       return true;
+                               }
+                               case 12: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore2 = getString();
+                                       for (int i = 0; i < thnStore.flags.size(); i++) {
+                                               if (strStore2.equalsIgnoreCase((String) thnStore.flags.get(i))) {
+                                                       return true;
+                                               }
+                                       }
+                                       return false;
+                               }
+                               case 13: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore2 = getString();
+                                       for (int i = 0; i < thnStore.flags.size(); i++) {
+                                               if (strStore2.equalsIgnoreCase((String) thnStore.flags.get(i))) {
+                                                       thnStore.flags.remove(i);
+                                                       if (vctVisibleUpdate != null || vctVisibleUpdate.contains(thnStore)) {
+                                                               vctVisibleUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                       }
+                                       return true;
+                               }
+                               case 14: {
+                                       engGame.varVariables.addVariable(readScript(), getLivingThing(getString()));
+                                       engGame.blnVariableListChanged = true;
+                                       return true;
+                               }
+                               case 15: {
+                                       engGame.varVariables.addVariable(readScript(), parseValue());
+                                       engGame.blnVariableListChanged = true;
+                                       return true;
+                               }
+                               case 16: {
+                                       engGame.varVariables.addVariable(readScript(), getString());
+                                       engGame.blnVariableListChanged = true;
+                                       return true;
+                               }
+                               case 17: {
+                                       varVariables.addVariable(readScript(), getLivingThing(getString()));
+                                       return true;
+                               }
+                               case 18: {
+                                       varVariables.addVariable(readScript(), parseValue());
+                                       return true;
+                               }
+                               case 19: {
+                                       varVariables.addVariable(readScript(), getString());
+                                       return true;
+                               }
+                               case 20: {
+                                       return (parseScript() | parseScript());
+                               }
+                               case 21: {
+                                       return (parseScript() & parseScript());
+                               }
+                               case 22: {
+                                       return (parseValue() < parseValue());
+                               }
+                               case 23: {
+                                       return (parseValue() > parseValue());
+                               }
+                               case 24: {
+                                       return (parseValue() == parseValue());
+                               }
+                               case 25: {
+                                       if (getLivingThing(getString()).battle != null) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 26: {
+                                       if (getLivingThing(getString()).clan.equalsIgnoreCase(getString())) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 27: {
+                                       if (getLivingThing(getString()).race.equalsIgnoreCase(getString())) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 28: {
+                                       if (getLivingThing(getString()).getItem(getString()) != null) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 29: {
+                                       Mob mobStore = new Mob(getString(), (int) parseValue(), (int) parseValue(), engGame);
+                                       //engGame.vctMobs.add(mobStore);
+                                       engGame.addDuskObject(mobStore);
+                                       return true;
+                               }
+                               case 30: {
+                                       Mob mobStore = new Mob(getString(), (int) parseValue(), (int) parseValue(), engGame);
+                                       mobStore.blnOneUse = true;
+                                       //engGame.vctMobs.add(mobStore);
+                                       engGame.addDuskObject(mobStore);
+                                       return true;
+                               }
+                               case 31: {
+                                       Item itmStore = engGame.getItem(getString());
+                                       itmStore.x = (int) parseValue();
+                                       itmStore.y = (int) parseValue();
+                                       engGame.addDuskObject(itmStore);
+                                       return true;
+                               }
+                               case 59: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore2 = getString();
+                                       int i = strStore2.indexOf(".");
+                                       int intNum = 1;
+                                       if (i != -1) {
+                                               try {
+                                                       intNum = Integer.parseInt(strStore2.substring(0, i));
+                                                       strStore2 = strStore2.substring(i + 1, strStore2.length());
+                                               } catch (NumberFormatException e) {
+                                                       intNum = 1;
+                                               }
+                                       }
+                                       Item itmStore = engGame.getItem(strStore2);
+                                       if (itmStore != null) {
+                                               // FIXME: put this in addItem() accessor on LivingThing
+                                               while (intNum > 0) {
+                                                       thnStore.itemList.addElement(itmStore);
+                                                       itmStore.onGetItem(engGame, thnStore);
+                                                       intNum--;
+                                               }
+                                               thnStore.updateItems();
+                                       }
+                                       return true;
+                               }
+                               case 33: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       thnStore.getItemAndRemove(getString());
+                                       thnStore.updateItems();
+                                       return true;
+                               }
+                               case 34: {
+                                       return getLivingThing(getString()).isWearing(getString());
+                               }
+                               case 35: {
+                                       getLivingThing(getString()).unWear(getString());
+                                       return true;
+                               }
+                               case 36: {
+                                       String strStore2 = readScript();
+                                       Variable varStore = null;
+                                       if (strStore2.equalsIgnoreCase("global")) {
+                                               varStore = engGame.varVariables.getVariable(readScript());
+                                       } else {
+                                               varStore = varVariables.getVariable(strStore2);
+                                       }
+                                       if (varStore != null && varStore.isNumber()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 37: {
+                                       String strStore2 = readScript();
+                                       Variable varStore = null;
+                                       if (strStore2.equalsIgnoreCase("global")) {
+                                               varStore = engGame.varVariables.getVariable(readScript());
+                                       } else {
+                                               varStore = varVariables.getVariable(strStore2);
+                                       }
+                                       if (varStore != null && varStore.isString()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 38: {
+                                       String strStore2 = readScript();
+                                       Variable varStore = null;
+                                       if (strStore2.equalsIgnoreCase("global")) {
+                                               varStore = engGame.varVariables.getVariable(readScript());
+                                       } else {
+                                               varStore = varVariables.getVariable(strStore2);
+                                       }
+                                       if (varStore != null && varStore.isLivingThing()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 39: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       if (thnStore != null && thnStore.isPlayer()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 40: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       if (thnStore != null && thnStore.isPet()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 41: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       if (thnStore != null && thnStore.isMob()) {
+                                               return true;
+                                       }
+                                       return false;
+                               }
+                               case 42: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore2 = getString();
+                                       int intIndex = strStore2.indexOf("\n");
+                                       while (intIndex != -1) {
+                                               thnStore.chatMessage(strStore2.substring(0, intIndex));
+                                               strStore2 = strStore2.substring(intIndex + 1);
+                                               intIndex = strStore2.indexOf("\n");
+                                       }
+                                       thnStore.chatMessage(strStore2);
+                                       return true;
+                               }
+                               case 43: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       int red = (int) parseValue();
+                                       int green = (int) parseValue();
+                                       int blue = (int) parseValue();
+                                       String strStore2 = getString();
+                                       int intIndex = strStore2.indexOf("\n");
+                                       while (intIndex != -1) {
+                                               thnStore.chatMessage(red, green, blue, strStore2.substring(0, intIndex));
+                                               strStore2 = strStore2.substring(intIndex + 1);
+                                               intIndex = strStore2.indexOf("\n");
+                                       }
+                                       thnStore.chatMessage(red, green, blue, strStore2);
+                                       return true;
+                               }
+                               case 44: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       bytCommand = rafScript.readByte();
+                                       switch (bytCommand) {
+                                               case 0: {
+                                                       // FIXME: hp damage/adjustment if in battle, should send it through as a message
+                                                       thnStore.hp += (int) parseValue();
+                                                       if (thnStore.hp > (thnStore.maxhp + thnStore.hpbon)) {
+                                                               thnStore.hp = (thnStore.maxhp + thnStore.hpbon);
+                                                       }
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 1: {
+                                                       thnStore.maxhp += (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 2: {
+                                                       thnStore.hpbon += (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 3: {
+                                                       thnStore.mp += (int) parseValue();
+                                                       if (thnStore.mp > (thnStore.maxmp + thnStore.mpbon)) {
+                                                               thnStore.mp = (thnStore.maxmp + thnStore.mpbon);
+                                                       }
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 4: {
+                                                       thnStore.maxmp += (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 5: {
+                                                       thnStore.mpbon += (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 6: {
+                                                       thnStore.damageDone += (int) parseValue();
+                                                       return true;
+                                               }
+                                               case 7: {
+                                                       thnStore.stre += (int) parseValue();
+                                                       if (thnStore.stre > thnStore.stre_limit) {
+                                                               thnStore.stre = thnStore.stre_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 8: {
+                                                       thnStore.inte += (int) parseValue();
+                                                       if (thnStore.inte > thnStore.inte_limit) {
+                                                               thnStore.inte = thnStore.inte_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 9: {
+                                                       thnStore.dext += (int) parseValue();
+                                                       if (thnStore.dext > thnStore.dext_limit) {
+                                                               thnStore.dext = thnStore.dext_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 10: {
+                                                       thnStore.wisd += (int) parseValue();
+                                                       if (thnStore.wisd > thnStore.wisd_limit) {
+                                                               thnStore.wisd = thnStore.wisd_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 11: {
+                                                       thnStore.cons += (int) parseValue();
+                                                       if (thnStore.cons > thnStore.cons_limit) {
+                                                               thnStore.cons = thnStore.cons_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 12: {
+                                                       thnStore.strebon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 13: {
+                                                       thnStore.intebon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 14: {
+                                                       thnStore.dextbon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 15: {
+                                                       thnStore.wisdbon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 16: {
+                                                       thnStore.consbon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 17: {
+                                                       thnStore.acbon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 18: {
+                                                       thnStore.dammodbon += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 19: {
+                                                       thnStore.changeLocBypass((int) parseValue() + thnStore.x, thnStore.y);
+                                                       return true;
+                                               }
+                                               case 20: {
+                                                       thnStore.changeLocBypass(thnStore.x, (int) parseValue() + thnStore.y);
+                                                       return true;
+                                               }
+                                               case 21: {
+                                                       thnStore.changeLocBypass((int) parseValue() + thnStore.x, (int) parseValue() + thnStore.y);
+                                                       return true;
+                                               }
+                                               case 22: {
+                                                       thnStore.exp += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 23: {
+                                                       thnStore.cash += (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 24: {
+                                                       String strStore2 = getString();
+                                                       int intAddValue = (int) parseValue();
+                                                       thnStore.addToSkill(strStore2, intAddValue);
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                       }
+                               }
+                               case 45: {
+
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       bytCommand = rafScript.readByte();
+                                       switch (bytCommand) {
+                                               case 0: {
+                                                       thnStore.hp = (int) parseValue();
+                                                       if (thnStore.hp > (thnStore.maxhp + thnStore.hpbon)) {
+                                                               thnStore.hp = (thnStore.maxhp + thnStore.hpbon);
+                                                       }
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 1: {
+                                                       thnStore.maxhp = (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 2: {
+                                                       thnStore.hpbon = (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 3: {
+                                                       thnStore.mp = (int) parseValue();
+                                                       if (thnStore.mp > (thnStore.maxmp + thnStore.mpbon)) {
+                                                               thnStore.mp = (thnStore.maxmp + thnStore.mpbon);
+                                                       }
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 4: {
+                                                       thnStore.maxmp = (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 5: {
+                                                       thnStore.mpbon = (int) parseValue();
+                                                       thnStore.updateInfo();
+                                                       return true;
+                                               }
+                                               case 6: {
+                                                       thnStore.damageDone = (int) parseValue();
+                                                       return true;
+                                               }
+                                               case 7: {
+                                                       thnStore.stre = (int) parseValue();
+                                                       if (thnStore.stre > thnStore.stre_limit) {
+                                                               thnStore.stre = thnStore.stre_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 8: {
+                                                       thnStore.inte = (int) parseValue();
+                                                       if (thnStore.inte > thnStore.inte_limit) {
+                                                               thnStore.inte = thnStore.inte_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 9: {
+                                                       thnStore.dext = (int) parseValue();
+                                                       if (thnStore.dext > thnStore.dext_limit) {
+                                                               thnStore.dext = thnStore.dext_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 10: {
+                                                       thnStore.wisd = (int) parseValue();
+                                                       if (thnStore.wisd > thnStore.wisd_limit) {
+                                                               thnStore.wisd = thnStore.wisd_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 11: {
+                                                       thnStore.cons = (int) parseValue();
+                                                       if (thnStore.cons > thnStore.cons_limit) {
+                                                               thnStore.cons = thnStore.cons_limit;
+                                                       }
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 12: {
+                                                       thnStore.strebon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 13: {
+                                                       thnStore.intebon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 14: {
+                                                       thnStore.dextbon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 15: {
+                                                       thnStore.wisdbon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 16: {
+                                                       thnStore.consbon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 17: {
+                                                       thnStore.acbon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 18: {
+                                                       thnStore.dammodbon = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 19: {
+                                                       thnStore.changeLocBypass((int) parseValue(), thnStore.y);
+                                                       return true;
+                                               }
+                                               case 20: {
+                                                       thnStore.changeLocBypass(thnStore.x, (int) parseValue());
+                                                       return true;
+                                               }
+                                               case 21: {
+                                                       thnStore.changeLocBypass((int) parseValue(), (int) parseValue());
+                                                       return true;
+                                               }
+                                               case 22: {
+                                                       thnStore.exp = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 23: {
+                                                       thnStore.cash = (int) parseValue();
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                               case 24: {
+                                                       String strStore2 = getString();
+                                                       int intNewValue = (int) parseValue();
+                                                       thnStore.setSkill(strStore2, intNewValue);
+                                                       if (vctUpdate != null || vctUpdate.contains(thnStore)) {
+                                                               vctUpdate.addElement(thnStore);
+                                                       }
+                                                       return true;
+                                               }
+                                       }
+                               }
+                               case 46: {
+                                       int dbgX, dbgY;
+                                       short dbgValue;
+                                       dbgX = (int) parseValue();
+                                       dbgY = (int) parseValue();
+                                       dbgValue = (short) parseValue();
+                                       if (dbgValue == 0) {
+                                               engGame.log.printMessage(Log.DEBUG, "Script " + strName + " called changeMap with 0 at " + dbgX + "," + dbgY);
+                                       }
+//                                     engGame.changeMap((int)parseValue(),(int)parseValue(),(short)parseValue());
+                                       engGame.changeMap(dbgX, dbgY, dbgValue);
+                                       return true;
+                               }
+                               case 47: {
+                                       String strOne = getString();
+                                       return strOne.equalsIgnoreCase(getString());
+                               }
+                               case 48: {
+                                       String strInput = "";
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       if (!thnStore.isPlayer()) {
+                                               engGame.log.printMessage(Log.ERROR, "parseScript():In script " + strName + ", attempt to get input from non-player");
+                                               return false;
+                                       }
+                                       if (true)
+                                               // FIXME: protocol implementation
+                                               throw new RuntimeException("cannot ask questions yet");
+                                       // FIXME: this looks dodgy
+                                       // FIXME: move to livingthing
+                                       thnStore.halt();
+                                       thnStore.stillThere();  // This puts something in the buffer
+                                       thnStore.stillThere();  // Need to do this twice to ensure thnStore out of read loop
+                                       thnStore.connectionThread.sleep(750);  // wait for it...
+                                       try {
+                                               // Empty out the BufferedReader for the answer
+                                               //while (thnStore.instream.ready()) {
+                                               //      thnStore.instream.read();
+                                               //}
+                                       } catch (Exception e) {
+                                               engGame.log.printError("parseScript():While trying to empty read buffer to get player input", e);
+                                       }
+                                       strInput = thnStore.instream.readLine();
+                                       varVariables.addVariable(getString(), strInput);
+                                       thnStore.proceed();
+                                       return true;
+                               }
+                               case 49: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       engGame.notifyRemoved(thnStore);
+                                       engGame.addEntity(thnStore);
+                                       return true;
+                               }
+                               case 50: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore = getString();
+                                       if (thnStore == null) {
+                                               return true;
+                                       }
+                                       strStore = strStore.replace('\n', ' ');
+                                       if (thnStore.isPlayer()) {
+                                               strStore = "player " + thnStore.name + " " + strStore;
+                                       } else if (thnStore.isPet()) {
+                                               strStore = "pet " + thnStore.name + " " + strStore;
+                                       } else if (thnStore.isMob()) {
+                                               strStore = "mob " + thnStore.name + " " + strStore;
+                                       }
+                                       engGame.log.printMessage(Log.ALWAYS, "ScriptLog:" + strName + ":" + strStore);
+                                       return true;
+                               }
+                               case 51: {
+                                       String strStore = getString();
+                                       engGame.chatMessage(strStore, "default");
+                                       return true;
+                               }
+                               case 52: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strTitle = getString();
+                                       String strStore2 = getString();
+                                       String strLine = null;
+                                       int intIndex = strStore2.indexOf("\n");
+                                       thnStore.send((char) 20 + strTitle + "\n");
+                                       while (intIndex != -1) {
+                                               strLine = strStore2.substring(0, intIndex);
+                                               thnStore.send(strLine + "\n");
+                                               strStore2 = strStore2.substring(intIndex + 1);
+                                               intIndex = strStore2.indexOf("\n");
+                                       }
+                                       thnStore.send(strStore2 + "\n");
+                                       thnStore.send("--EOF--\n");
+                                       return true;
+                               }
+                               case 53: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       if (thnStore == null) {
+                                               return true;
+                                       }
+                                       String strWhat = getString();
+                                       if (strWhat == null) {
+                                               return true;
+                                       }
+                                       if (thnStore.isPlayer()) {
+                                               if (engGame.gplosemod != 0) {
+                                                       int gplost = (int) (thnStore.cash * engGame.gplosemod);
+                                                       thnStore.chatMessage("You have lost " + gplost + "gp.");
+                                                       thnStore.cash -= gplost;
+                                               }
+                                               if (engGame.explosemod != 0) {
+                                                       int explost = (int) (thnStore.exp * engGame.explosemod);
+                                                       thnStore.chatMessage("You have lost " + explost + "exp.");
+                                                       thnStore.exp -= explost;
+                                               }
+                                               engGame.chatMessage(thnStore.name + " has been killed by " + strWhat, "default");
+                                               if (engGame.scrOnDeath != null && thnStore.isWorking) {
+                                                       engGame.scrOnDeath.varVariables.clearVariables();
+                                                       engGame.scrOnDeath.varVariables.addVariable("trigger", thnStore);
+                                                       engGame.scrOnDeath.runScript();
+                                               }
+                                       }
+                                       return true;
+                               }
+                               case 54: {
+                                       LivingThing thnStore = getLivingThing("trigger");
+                                       if (thnStore != null && thnStore.isLivingThing()) {
+                                               thnStore.isAlwaysCommands = false;
+                                       }
+                                       return true;
+                               }
+                               case 55: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strClanName = getString();
+                                       if (engGame.isGoodName(strClanName)) {
+                                               thnStore.clan = strClanName;
+                                               if (thnStore.privs < 1) {
+                                                       thnStore.privs = 1;
+                                               }
+                                       }
+                                       return true;
+                               }
+                               case 56: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strClanName = getString();
+                                       if (engGame.isGoodName(strClanName)) {
+                                               thnStore.clan = strClanName;
+                                               if (thnStore.privs == 1) {
+                                                       thnStore.privs = 0;
+                                               }
+                                       }
+                                       if (vctVisibleUpdate != null || vctVisibleUpdate.contains(thnStore)) {
+                                               vctVisibleUpdate.addElement(thnStore);
+                                       }
+                                       return true;
+                               }
+                               case 57: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       thnStore.lastMessageStamp = 0;
+                                       return true;
+                               }
+                               case 58: {
+                                       LivingThing thnStore = getLivingThing(getString());
+                                       String strStore2 = getString();
+                                       int intIndex = strStore2.indexOf("\n");
+                                       while (intIndex != -1) {
+                                               if (thnStore.battle != null && thnStore.popup) {
+                                                       thnStore.send("" + (char) 33 + strStore2.substring(0, intIndex + 1));
+                                               } else {
+                                                       thnStore.chatMessage(strStore2.substring(0, intIndex));
+                                               }
+                                               strStore2 = strStore2.substring(intIndex + 1);
+                                               intIndex = strStore2.indexOf("\n");
+                                       }
+                                       if (thnStore.battle != null && thnStore.popup) {
+                                               thnStore.send("" + (char) 33 + strStore2 + "\n");
+                                       } else {
+                                               thnStore.chatMessage(strStore2);
+                                       }
+                                       return true;
+                               }
+                               case 32: {
+                                       return true;
+                               }
+                               /*case 127:
+                                {      
+                                return false;
+                                }*/
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("parseScript():While parsing byte(" + bytCommand + ") of script " + strName + " at line " + intLine, e);
+                       return false;
+               }
+               engGame.log.printMessage(Log.ERROR, "parseScript():Unknown byte(" + bytCommand + ") parsing script " + strName + " at line " + intLine);
+               return false;
+       }
+
+       private String parseValueForCompile() {
+               try {
+                       String strStore = readScriptForCompile();
+                       //functions:
+                       if (strStore.equals("+")) {
+                               return ("+ " + parseValueForCompile() + parseValueForCompile());
+                       }
+                       if (strStore.equals("-")) {
+                               return ("- " + parseValueForCompile() + parseValueForCompile());
+                       }
+                       if (strStore.equals("*")) {
+                               return ("* " + parseValueForCompile() + parseValueForCompile());
+                       }
+                       if (strStore.equals("/")) {
+                               return ("/ " + parseValueForCompile() + parseValueForCompile());
+                       }
+                       if (strStore.equalsIgnoreCase("skill")) {
+                               return "skill " + readScriptForCompile() + " ";
+                       }
+                       return strStore + " ";
+               } catch (Exception e) {
+                       engGame.log.printError("parseValueForCompile():Compiling script " + strName, e);
+               }
+               return null;
+       }
+
+       private double parseValue() {
+               try {
+                       String strStore = getString();
+                       //functions:
+                       if (strStore.equals("+")) {
+                               return (parseValue() + parseValue());
+                       }
+                       if (strStore.equals("-")) {
+                               return (parseValue() - parseValue());
+                       }
+                       if (strStore.equals("*")) {
+                               return (parseValue() * parseValue());
+                       }
+                       if (strStore.equals("/")) {
+                               return (parseValue() / parseValue());
+                       }
+                       //random number:
+                       if (strStore.equalsIgnoreCase("rand")) {
+                               return Math.random();
+                       }
+                       //number:
+                       Double dblStore = getNumber(strStore);
+                       if (dblStore != null) {
+                               return dblStore.doubleValue();
+                       }
+                       //player qualities:
+                       LivingThing target = getLivingThing(strStore);
+                       strStore = getString();
+
+                       if (strStore.equalsIgnoreCase("cp")) {
+                               return (target.getCharacterPoints());
+                       }
+                       if (strStore.equalsIgnoreCase("tp")) {
+                               return (target.getTotalPoints());
+                       }
+                       if (strStore.equalsIgnoreCase("cash")) {
+                               return (target.cash);
+                       }
+                       if (strStore.equalsIgnoreCase("exp")) {
+                               return (target.exp);
+                       }
+                       if (strStore.equalsIgnoreCase("locx")) {
+                               return (target.x);
+                       }
+                       if (strStore.equalsIgnoreCase("locy")) {
+                               return (target.y);
+                       }
+                       if (strStore.equalsIgnoreCase("hp")) {
+                               return (target.hp);
+                       }
+                       if (strStore.equalsIgnoreCase("maxhp")) {
+                               return (target.maxhp + target.hpbon);
+                       }
+                       if (strStore.equalsIgnoreCase("mp")) {
+                               return (target.mp);
+                       }
+                       if (strStore.equalsIgnoreCase("maxmp")) {
+                               return (target.maxmp + target.mpbon);
+                       }
+                       if (strStore.equalsIgnoreCase("stre")) {
+                               return (target.stre + target.strebon);
+                       }
+                       if (strStore.equalsIgnoreCase("dext")) {
+                               return (target.dext + target.dextbon);
+                       }
+                       if (strStore.equalsIgnoreCase("inte")) {
+                               return (target.inte + target.intebon);
+                       }
+                       if (strStore.equalsIgnoreCase("wisd")) {
+                               return (target.wisd + target.wisdbon);
+                       }
+                       if (strStore.equalsIgnoreCase("cons")) {
+                               return (target.cons + target.consbon);
+                       }
+                       if (strStore.equalsIgnoreCase("dammod")) {
+                               return target.getDamModWithBonus();
+                       }
+                       if (strStore.equalsIgnoreCase("ac")) {
+                               return target.getArmorModWithBonus();
+                       }
+                       if (strStore.equalsIgnoreCase("privs")) {
+                               return target.privs;
+                       }
+                       if (strStore.equalsIgnoreCase("skill")) {
+                               String strStore2 = getString();
+                               int bytStore = target.getSkill(strStore2);
+                               if (bytStore == 0) {
+                                       bytStore = target.getSpell(strStore2);
+                               }
+                               return bytStore;
+                       }
+                       if (strStore.equalsIgnoreCase("count")) {
+                               String strStore2 = getString();
+                               List<Item> list = target.itemList.get(strStore2);
+                               long total = 0;
+                               if (list != null) {
+                                       total = list.size();
+                               }
+                               return total;
+                       }
+               } catch (Exception e) {
+                       engGame.log.printError("parseValue()", e);
+               }
+               return 0;
+       }
+}
diff --git a/DuskServer/src/duskz/server/ScriptManager.java b/DuskServer/src/duskz/server/ScriptManager.java
new file mode 100644 (file)
index 0000000..4e7ec06
--- /dev/null
@@ -0,0 +1,300 @@
+/*/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilePermission;
+import java.io.FileReader;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.CodeSource;
+import java.security.Permissions;
+import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadFactory;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.SimpleScriptContext;
+
+/**
+ * Manages the (javascript) engine
+ *
+ * Doing this securely is complicated, so is likely to be buggy and not really
+ * secure ...
+ *
+ * I found I had to create the script engine itself from the same doPrivileged()
+ * invocation or it simply broke the sanboxing. Hence all script execution is
+ * performed from a pool of threads created from the same sandbox.
+ *
+ * Another thread monitors the pool checking for out of control scripts (i.e.
+ * they take too long to run).
+ *
+ * @author notzed
+ */
+public class ScriptManager {
+
+       AccessControlContext ac;
+       ScriptEngine engine;
+       LinkedBlockingDeque<ScriptData> queue = new LinkedBlockingDeque<>();
+       int nthreads = 2;
+       ExecutorService pool;
+       static ThreadLocal<ScriptContext> contexts;
+       // some sort of shit here for monitoring threads
+       HashMap<Thread, Long> active = new HashMap<>();
+
+       public ScriptManager() {
+               Permissions perms = new Permissions();
+               //perms.add(new AllPermission());
+               perms.add(new FilePermission("scripts/*", "read,write"));
+               //      perms.add(new NetPermission("*"));
+               //perms.add(new RuntimePermission("accessDeclaredMembers"));
+               // Cast to Certificate[] required because of ambiguity:
+               ProtectionDomain domain = new ProtectionDomain(new CodeSource(null, (Certificate[]) null), perms);
+               ac = new AccessControlContext(new ProtectionDomain[]{domain});
+       }
+
+       public void start() {
+               AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                       @Override
+                       public Object run() {
+                               // If the engine is created here it needs to be used here too.
+                               ScriptEngineManager factory = new ScriptEngineManager();
+                               engine = factory.getEngineByName("JavaScript");
+                               contexts = new ThreadLocal<>();
+                               pool = Executors.newFixedThreadPool(2, new ThreadFactory() {
+                                       @Override
+                                       public Thread newThread(Runnable r) {
+                                               Thread t = new Thread(r);
+
+                                               t.setDaemon(true);
+                                               return t;
+                                       }
+                               });
+
+                               // TOOD: anything else I want to do here?  A management/monitoring thread?
+
+                               return null;
+                       }
+               }, ac);
+
+               new WatchThread().start();
+       }
+
+       public Future<?> runScript(String script, Object... args) {
+               return pool.submit(new ScriptData(script, args));
+       }
+
+       public Future<?> runScript(File script, Object... args) throws FileNotFoundException {
+               return pool.submit(new ScriptData(script, args));
+       }
+
+       synchronized void startJob(Thread t) {
+               active.put(t, System.currentTimeMillis());
+       }
+
+       synchronized void endJob(Thread t) {
+               active.remove(t);
+       }
+
+       synchronized void watchdog() {
+               // So there is no way to interrupt the executing thread!
+               // Well it mozilla code after-all ...
+
+               // So i'm forced to use stop with all its apparent dangers.
+
+               long now = System.currentTimeMillis();
+               for (Entry<Thread, Long> e : active.entrySet()) {
+                       if ((now - e.getValue()) > 1000) {
+                               System.out.println("Job taking too long, interrupting it!");
+                               //e.getKey().interrupt();
+                               e.getKey().stop();
+                       }
+               }
+       }
+
+       class WatchThread extends Thread {
+
+               public WatchThread() {
+                       setDaemon(true);
+               }
+
+               @Override
+               public void run() {
+                       while (true) {
+                               try {
+                                       sleep(1000);
+
+                                       watchdog();
+                               } catch (InterruptedException ex) {
+                                       Logger.getLogger(ScriptManager.class.getName()).log(Level.SEVERE, null, ex);
+                               }
+                       }
+               }
+       };
+
+       class ScriptData<T> implements Callable<T> {
+
+               FileReader scriptReader;
+               String script;
+               Map<String, Object> args = new HashMap<>();
+
+               public ScriptData(String script, Object... args) {
+                       for (int i = 0; i < args.length; i += 2) {
+                               this.args.put((String) args[i], args[i + 1]);
+                       }
+                       this.script = script;
+               }
+
+               public ScriptData(File scriptFile, Object... args) throws FileNotFoundException {
+                       for (int i = 0; i < args.length; i += 2) {
+                               this.args.put((String) args[i], args[i + 1]);
+                       }
+                       this.scriptReader = new FileReader(scriptFile);
+               }
+
+               @Override
+               public T call() throws Exception {
+                       T res = null;
+                       try {
+                               ScriptContext ctx = contexts.get();
+                               if (ctx == null) {
+                                       ctx = new SimpleScriptContext();
+                                       contexts.set(ctx);
+                               }
+                               Bindings b = ctx.getBindings(ScriptContext.ENGINE_SCOPE);
+
+                               b.clear();
+                               b.putAll(args);
+
+                               startJob(Thread.currentThread());
+                               if (scriptReader != null)
+                                       res = (T) engine.eval(scriptReader, b);
+                               else
+                                       res = (T) engine.eval(script, b);
+                               //                      lastStart = -1;
+                               b.clear();
+                       } finally {
+                               endJob(Thread.currentThread());
+                               if (scriptReader != null)
+                                       scriptReader.close();
+                       }
+                       return res;
+               }
+       };
+
+       public static void main(String[] args) {
+               // Lets see if it the security shit works
+               ScriptManager sm = new ScriptManager();
+
+               sm.start();
+
+               Future f;
+
+               try {
+                       f = sm.runScript("1;");
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       ex.printStackTrace(System.out);
+               }
+               try {
+                       f = sm.runScript("if (true) 0; else 1;");
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+
+               try {
+                       String s = "var out = new java.io.FileOutputStream('hack-thread.txt');"
+                                       + " out.write(65);"
+                                       + "out.close();"
+                                       + " println('wrote hack.txt ok');";
+
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       f = sm.runScript(new File("hack.script"));
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       String s = "var out = new java.io.FileInputStream('hack.script');"
+                                       + "out.close();"
+                                       + " println('read hack.script ok');";
+
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       String s = "while (true);";
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       String s = "while (true);";
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       String s = "var out = new java.io.FileOutputStream('scripts/newscript');"
+                                       + " out.write(65);"
+                                       + "out.close();"
+                                       + " println('wrote scripts/newscript ok');";
+
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+               try {
+                       String s = "while (true);";
+                       f = sm.runScript(s);
+                       System.out.println("result = " + f.get());
+               } catch (Exception ex) {
+                       System.out.println(ex);
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/SpellGroup.java b/DuskServer/src/duskz/server/SpellGroup.java
new file mode 100644 (file)
index 0000000..e853cc3
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised collections
+ */
+package duskz.server;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * SpellGroup contains all the spells in one group. It provides methods to
+ * decide how much a spell will cost the player to cast.
+ *
+ * @author Tom Weingarten
+ */
+public class SpellGroup {
+
+       public final String strName;
+       public final List<String> vctSpells = new ArrayList<>();
+
+       public SpellGroup(String inName) {
+               strName = inName;
+       }
+
+       int getSpellPercent(String strName) {
+               int i = getSpellNumber(strName);
+               if (i > 0) {
+                       i = (100 * i) / (vctSpells.size() - 1);
+               }
+               return i;
+               /*
+                String strStore;
+                for (int i = 0; i < vctSpells.size(); i++) {
+                strStore = (String) vctSpells.elementAt(i);
+                if (strStore.equals(strName)) {
+                if (i == 0) {
+                return 0;
+                } else {
+                return (100 * i) / (vctSpells.size() - 1);
+                }
+                }
+                }
+                return -1;*/
+       }
+
+       public int getSpellNumber(String strName) {
+               return vctSpells.indexOf(strName);
+               /*
+                String strStore;
+                for (int i = 0; i < vctSpells.size(); i++) {
+                strStore = (String) vctSpells.elementAt(i);
+                if (strStore.equals(strName)) {
+                return i;
+                }
+                }
+                return -1;*/
+       }
+
+       public String spellList(int percent) {
+               String strStore;
+
+               if (vctSpells.isEmpty()) {
+                       return "";
+               }
+
+               StringBuilder sb = new StringBuilder();
+
+               strStore = (String) vctSpells.get(0);
+               if (strStore == null) {
+                       return "";
+               }
+               sb.append("  ").append((110 - percent) / 2).
+                               append(" mp) ").
+                               append(strStore).append("\n");
+               for (int i = 1; i < vctSpells.size(); i++) {
+                       if (percent < (100 * i) / (vctSpells.size() - 1)) {
+                               break;
+                       }
+                       strStore = (String) vctSpells.get(i);
+                       sb.append("  ").append((110 - (percent - (100 * i) / (vctSpells.size() - 1))) / 2)
+                                       .append(" mp) ").append(strStore).append("\n");
+               }
+               return sb.toString();
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/TickThread.java b/DuskServer/src/duskz/server/TickThread.java
new file mode 100644 (file)
index 0000000..4c018e6
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - Modernisation, fixed some locking issues
+ */
+package duskz.server;
+
+import duskz.server.entity.Mob;
+import duskz.server.entity.LivingThing;
+import java.util.Iterator;
+
+public class TickThread implements Runnable {
+
+       DuskEngine game;
+       long now = System.currentTimeMillis(),
+                       delay = 0;
+       int tick = 0;
+
+       TickThread(DuskEngine inGame) {
+               this.game = inGame;
+       }
+
+       public void run() {
+               while (true) {
+                       try {
+                               //1000 milliseconds(1 second) per tick
+                               delay = 1000L - (System.currentTimeMillis() - now);
+                               if (delay > 0) {
+                                       Thread.currentThread().sleep(delay);
+                               }
+                               now = System.currentTimeMillis();
+
+                               // FIXME: similar code is also in DuskEngine, all unlocked??
+
+                               synchronized (game.mobList) {
+                                       for (Mob mob : game.mobList) {
+                                               // FIXME: remove magic number!!
+                                               if (mob.x == -6) {
+                                                       mob.hp++;
+                                                       if (mob.hp > -1) {
+                                                               mob.changeLocBypass(mob.originalX, mob.originalY);
+                                                               mob.hp = mob.maxhp;
+                                                       }
+                                               } else {
+                                                       try {
+                                                               if (game.blnAI && mob.blnCanSeePlayer && (mob.fctFaction != null)) {
+                                                                       mob.fctFaction.runAI(mob);
+                                                               }
+                                                       } catch (Exception e) {
+                                                               mob.blnCanSeePlayer = false;
+                                                               game.log.printError("TickThread.run():While trying to runAI for mob \"" + mob.name + "\".", e);
+                                                       }
+                                                       mob.moveTick();
+                                               }
+                                       }
+                               }
+                               for (LivingThing lt : game.checkConditionList) {
+                                       for (Iterator<Condition> it = lt.conditions.iterator(); it.hasNext();) {
+                                               Condition cond = it.next();
+                                               if (cond.ticksPast >= cond.occurance) {
+                                                       cond.onOccurance(game, lt);
+                                                       if (cond.duration > 0) {
+                                                               cond.duration--;
+                                                       }
+                                                       if (cond.duration == 0) {
+                                                               cond.onEnd(game, lt);
+                                                               it.remove();
+                                                       }
+                                                       cond.ticksPast = 1;
+                                               } else {
+                                                       cond.ticksPast++;
+                                               }
+                                       }
+                               }
+
+                               if (tick > 120) {
+                                       tick = 0;
+                               }
+                               tick++;
+                       } catch (Exception e) {
+                               game.log.printError("ThreadTicks.run()", e);
+                       }
+               }
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/TrackerThread.java b/DuskServer/src/duskz/server/TrackerThread.java
new file mode 100644 (file)
index 0000000..d2cba7e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server;
+
+import duskz.server.entity.LivingThing;
+import java.net.DatagramSocket;
+import java.net.DatagramPacket;
+import java.net.InetAddress;
+
+public class TrackerThread implements Runnable {
+
+       DuskEngine engGame;
+       DatagramSocket sckTracker;
+
+       TrackerThread(DuskEngine inGame) {
+               engGame = inGame;
+       }
+
+       void initializeTracker() {
+               if (engGame.tracker && sckTracker == null) {
+                       try {
+                               engGame.log.printMessage(Log.ALWAYS, "Communicating with tracker");
+                               sckTracker = new DatagramSocket(engGame.trackerport);
+                               sckTracker.setSoTimeout(0); //no timeout
+                               String s1 = "\000" + engGame.trackername;
+                               DatagramPacket datagrampacket = new DatagramPacket(s1.getBytes(), s1.length());
+                               datagrampacket.setAddress(InetAddress.getByName("dusk.wesowin.org"));
+                               datagrampacket.setPort(7520);
+                               sckTracker.send(datagrampacket);
+                               s1 = "\002" + engGame.port;
+                               datagrampacket.setData(s1.getBytes());
+                               datagrampacket.setLength(s1.length());
+                               sckTracker.send(datagrampacket);
+                               if (!engGame.site.equals("none")) {
+                                       String s2 = "\003" + engGame.site;
+                                       datagrampacket.setData(s2.getBytes());
+                                       datagrampacket.setLength(s2.length());
+                                       sckTracker.send(datagrampacket);
+                               }
+                               engGame.tracker = true;
+                       } catch (Exception e) {
+                               engGame.log.printError("initializeTracker():Failed to contact tracker, disabling", e);
+                               sckTracker = null;
+                               engGame.tracker = false;
+                       }
+               }
+       }
+
+       void updateTrackerUsers() {
+               if (!engGame.tracker) {
+                       return;
+               }
+
+               try {
+                       int count = 0;
+                       for (LivingThing thnStore : engGame.playersByName.values()) {
+                               if (!(thnStore.privs > 2 && thnStore.hasCondition("invis"))) {
+                                       count++;
+                               }
+                       }
+                       String s = "\001" + count;
+                       DatagramPacket datagrampacket = new DatagramPacket(s.getBytes(), s.length());
+                       datagrampacket.setAddress(InetAddress.getByName("dusk.wesowin.org"));
+                       datagrampacket.setPort(7520);
+                       sckTracker.send(datagrampacket);
+               } catch (Exception e) {
+                       engGame.log.printError("updateTrackerUsers()", e);
+               }
+       }
+
+       void pingTracker() {
+               if (!engGame.tracker) {
+                       return;
+               }
+
+               DatagramPacket pckStore = new DatagramPacket(new byte[1], 1);
+
+               try {
+                       pckStore.setAddress(InetAddress.getByName("dusk.wesowin.org"));
+                       pckStore.setPort(7520);
+                       pckStore.setData("\005".getBytes());
+                       pckStore.setLength(1);
+                       sckTracker.send(pckStore);
+               } catch (Exception e) {
+                       engGame.log.printError("pingTracker():While communicating with tracker", e);
+                       sckTracker = null;
+                       engGame.tracker = false;
+               }
+       }
+
+       void removeFromTracker() {
+               if (!engGame.tracker) {
+                       return;
+               }
+
+               try {
+                       String s = "\004";
+                       DatagramPacket datagrampacket = new DatagramPacket(s.getBytes(), s.length());
+                       datagrampacket.setAddress(InetAddress.getByName("dusk.wesowin.org"));
+                       datagrampacket.setPort(7520);
+                       sckTracker.send(datagrampacket);
+               } catch (Exception e) {
+                       engGame.log.printError("removeFromTracker()", e);
+               }
+       }
+
+       public void run() {
+               if (!engGame.tracker) {
+                       return;
+               }
+
+               engGame.log.printMessage(Log.ALWAYS, "Starting tracker thread");
+
+               initializeTracker();
+
+               while (engGame.tracker) {
+                       try {
+                               Thread.currentThread().sleep(300000);
+                       } catch (Exception e) {
+                               engGame.log.printError("TrackerThread.run()", e);
+                       }
+                       updateTrackerUsers();
+                       pingTracker();
+               }
+
+               removeFromTracker();
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/Variable.java b/DuskServer/src/duskz/server/Variable.java
new file mode 100644 (file)
index 0000000..8b448cf
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - separated out from VariableSet for public access
+ */
+package duskz.server;
+
+/**
+ * Holder for variables.
+ *
+ * TODO: make this OO. Will need fixing for javascript.
+ *
+ * @author notzed
+ */
+public class Variable {
+
+       String strName;
+       Object objData;
+       byte bytType;
+       public final static byte NUMBER = 0;
+       public final static byte STRING = 1;
+       public final static byte THING = 2;
+
+       public Variable(String strName, Object objData, byte bytType) {
+               this.strName = strName;
+               this.objData = objData;
+               this.bytType = bytType;
+       }
+
+       public double doubleValue() {
+               return (Double) objData;
+       }
+
+       public int intValue() {
+               return ((Number) objData).intValue();
+       }
+
+       //0-Number
+       //1-String
+       //2-LivingThing
+       //3-Item
+       boolean isNumber() {
+               if (bytType == 0) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isString() {
+               if (bytType == 1) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isLivingThing() {
+               if (bytType == 2) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isItem() {
+               if (bytType == 3) {
+                       return true;
+               }
+               return false;
+       }
+}
diff --git a/DuskServer/src/duskz/server/VariableSet.java b/DuskServer/src/duskz/server/VariableSet.java
new file mode 100644 (file)
index 0000000..4849471
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, separated out Variable.
+ */
+package duskz.server;
+
+import duskz.server.entity.LivingThing;
+import java.util.HashMap;
+
+/**
+ * Contains a set of variables for use in a DuskScript. Variables may be of type
+ * number, livingthing, or string.
+ *
+ * @author Tom Weingarten
+ */
+public class VariableSet {
+
+       //Vector vctVariables;
+       public final HashMap<String, Variable> vctVariables = new HashMap<>();
+
+       public VariableSet() {
+       }
+
+       public void clearVariables() {
+               vctVariables.clear();
+       }
+
+       protected void addVariable(Variable v) {
+               String n = v.strName.toLowerCase();
+               if (n.equals("name")
+                               || n.equals("clan")
+                               || n.equals("concat")) {
+//                     engGame.log.printMessage(Log.ERROR, "addVariable():You cannot create a variable with the name \""+strName+"\".");
+                       return;
+               }
+               vctVariables.put(n, v);
+       }
+
+       public void addVariable(String strName, Double objIn) {
+               addVariable(new Variable(strName, objIn, Variable.NUMBER));
+       }
+
+       public void addVariable(String strName, double objIn) {
+               addVariable(new Variable(strName, objIn, Variable.NUMBER));
+       }
+
+       public void addVariable(String strName, String objIn) {
+               addVariable(new Variable(strName, objIn, Variable.STRING));
+       }
+
+       public void addVariable(String strName, LivingThing objIn) {
+               addVariable(new Variable(strName, objIn, Variable.THING));
+       }
+
+       /*void addVariable(String strName, Item objIn)
+        {
+        if (strName.equalsIgnoreCase("name")
+        ||strName.equalsIgnoreCase("clan")
+        ||strName.equalsIgnoreCase("concat"))
+        {
+        //                     engGame.log.printMessage(Log.ERROR, "addVariable():You cannot create a variable with the name \""+strName+"\".");
+        return;
+        }
+        Variable varStore;
+        for (int i=0;i<vctVariables.size();i++)
+        {
+        varStore = (Variable)vctVariables.elementAt(i);
+        if (varStore.strName.equals(strName))
+        {
+        vctVariables.removeElementAt(i);
+        break;
+        }
+        }
+        varStore = new Variable();
+        varStore.strName = strName;
+        varStore.objData = objIn;
+        varStore.bytType = 3;
+        vctVariables.addElement(varStore);
+        }*/
+       public Variable getVariable(String strName) {
+               return vctVariables.get(strName.toLowerCase());
+       }
+
+       public void removeVariable(String strName) {
+               vctVariables.remove(strName.toLowerCase());
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Ability.java b/DuskServer/src/duskz/server/entity/Ability.java
new file mode 100644 (file)
index 0000000..60cee74
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server.entity;
+
+/**
+ * Base class for trained attributes.
+ *
+ * Training goes up to 100.
+ *
+ * FIXME: there's something major wrong with abilities!!
+ *
+ * @author notzed
+ */
+public class Ability {
+
+       private int ability;
+       public final String name;
+
+       public Ability(String name) {
+               this.name = name;
+       }
+
+       public Ability(int ability, String name) {
+               ability = Math.max(ability, 0);
+               ability = Math.min(ability, 100);
+               this.ability = ability;
+               this.name = name;
+       }
+
+       public void setAbility(int ability) {
+               ability = Math.max(ability, 0);
+               ability = Math.min(ability, 100);
+               this.ability = ability;
+       }
+
+       /**
+        * Train an ability.
+        *
+        * @param delta
+        * @return true if the ability was increased, false if it is already at maximum
+        */
+       public boolean train(int delta) {
+               if (ability < 100) {
+                       setAbility(ability + delta);
+                       return true;
+               }
+               return false;
+       }
+
+       public int getAbility() {
+               return ability;
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/DuskObject.java b/DuskServer/src/duskz/server/entity/DuskObject.java
new file mode 100644 (file)
index 0000000..fb48dc3
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, added list functions and
+ * serialisation..
+ */
+package duskz.server.entity;
+
+import duskz.protocol.MessageType;
+import duskz.protocol.ServerMessage;
+import duskz.protocol.ServerMessage.EntityMessage;
+
+/*
+ All code copyright Tom Weingarten (captaint@home.com) 2000
+ Tom Weingarten makes no assurances as to the reliability or
+ functionality of this code. Use at your own risk. 
+
+ You are free to edit or redistribute this code or any portion
+ at your wish, under the condition that you do not edit or 
+ remove this license, and accompany it with all redistributions.
+ */
+/**
+ * DuskObject is the basic type of entity in Dusk.
+ *
+ * @author Tom Weingarten
+ */
+public abstract class DuskObject {
+
+       public static final byte LIVING_THING = 0;
+       public static final byte ITEM = 1;
+       public static final byte PROP = 2;
+       public static final byte SIGN = 3;
+       public static final byte MERCHANT = 4;
+       public static final byte PLAYER_MARCHANT = 5;
+       final public long ID;                                   // Unique ID if this object
+       public String name;             // Name of this object
+       public String description = null;       // Description of this object
+       boolean isHideName;             // if true: Do not display object's name on the client map.
+       public int x, y;
+       DuskObject next = null; //Linked List
+
+       public DuskObject(long ID, String name) {
+               this.ID = ID;
+               this.name = name;
+       }
+
+       public DuskObject(byte bytObjType, long ID) {
+               this.ID = ID;
+       }
+
+       public abstract byte getType();
+
+       public abstract int getImage();
+       // for some fucked reason this doesn't match getType()
+
+       public abstract int getEntityType();
+
+       // These are a bit dumb - we have objects to change behaviour.
+       public boolean isLivingThing() {
+               return getType() == LIVING_THING;
+       }
+
+       public boolean isItem() {
+               return getType() == ITEM;
+       }
+
+       public boolean isProp() {
+               return getType() == PROP;
+       }
+
+       public boolean isSign() {
+               return getType() == SIGN;
+       }
+
+       public boolean isMerchant() {
+               return getType() == MERCHANT;
+       }
+
+       public boolean isPlayerMerchant() {
+               return getType() == PLAYER_MARCHANT;
+       }
+
+       public long getID() {
+               return ID;
+       }
+
+       /**
+        * Convert to on-wire entity format
+        *
+        * @param eng
+        * @return
+        */
+       public String toEntity() {
+               StringBuilder sb = new StringBuilder();
+
+               sb.append(name).append('\n');
+               sb.append(getEntityType()).append('\n');
+               sb.append(ID).append('\n');
+               sb.append(x).append('\n');
+               sb.append(y).append('\n');
+               sb.append(getImage()).append('\n');
+
+               return sb.toString();
+       }
+
+       public EntityMessage toMessage(MessageType type) {
+               return new ServerMessage.EntityMessage(type, ID, name,
+                               (byte) getEntityType(), (short) x, (short) y, (short) getImage(), (short) -1);
+       }
+
+       // Linked list stuff - should it just use a container?
+       public DuskObject getNext() {
+               return next;
+       }
+
+       /**
+        * Measure the distance between two objects.
+        *
+        * @param o Other object
+        * @return integer version of Euclidian distance.
+        */
+       public int distance(DuskObject o) {
+               int dx = o.x - x;
+               int dy = o.y - y;
+
+               return (int) Math.sqrt(dx * dx + dy * dy);
+       }
+
+       /**
+        * Measure the number of tile steps to get to the target. Just uses
+        * "Manhatten" distance.
+        *
+        * @param o
+        * @return
+        */
+       public int tileDistance(DuskObject o) {
+               return Math.abs(o.x - x) + Math.abs(o.y - y);
+       }
+
+       /**
+        * Calculate if this object is 1 block away in any cardinal direction
+        *
+        * @param o
+        * @return
+        */
+       public boolean adjacent(DuskObject o) {
+               return Math.abs(o.x - x) + Math.abs(o.y - y) <= 1;
+       }
+
+       @Override
+       public String toString() {
+               return getClass().getName() + " '" + name + "' @ " + x + "," + y;
+       }
+
+       @Deprecated
+       public static DuskObject find(DuskObject o, String name) {
+               while (o != null) {
+                       if (o.name.equalsIgnoreCase(name)) {
+                               break;
+                       }
+                       o = o.next;
+               }
+               return o;
+       }
+
+       /**
+        * append o to the end of the bucket chain from root
+        *
+        * @param root
+        * @param o
+        * @return if root is null then o, otherwise root
+        */
+       public static DuskObject append(DuskObject root, DuskObject o) {
+               if (o == root) {
+                       return root;
+               }
+
+               if (root == null) {
+                       o.next = null;
+                       return o;
+               }
+
+               DuskObject d = root;
+               while (d.next != null) {
+                       if (d == o) {
+                               return root;
+                       }
+                       d = d.next;
+               }
+               o.next = null;
+               d.next = o;
+
+               return root;
+       }
+
+       /**
+        * Remove o from a chain from root, returns new root
+        *
+        * @param root
+        * @param o
+        * @return
+        */
+       public static DuskObject remove(DuskObject root, DuskObject o) {
+               if (root == null) {
+                       return null;
+               } else if (root == o) {
+                       DuskObject n = o.next;
+                       o.next = null;
+                       return n;
+               } else {
+                       DuskObject d = root;
+                       while (d.next != null) {
+                               if (d.next == o) {
+                                       d.next = o.next;
+                                       o.next = null;
+                                       break;
+                               }
+                               d = d.next;
+                       }
+                       return root;
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Equipment.java b/DuskServer/src/duskz/server/entity/Equipment.java
new file mode 100644 (file)
index 0000000..5eb7d78
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, big refactor.
+ */
+package duskz.server.entity;
+
+import duskz.protocol.Wearing;
+
+/**
+ * Equipment contains all the Items a LivingThing is wearing.
+ *
+ * @author Tom Weingarten
+ */
+public class Equipment implements Wearing {
+
+       // Must match Wearing
+       public static final String[] USER_NAMES = {
+               "wield2", "arms2", "legs2", "torso2", "waist2", "neck2", "skull2", "eyes2", "hands2"
+       };
+       public static final float[] ARMOUR_MOD = {
+               0f, 0.05f, 0.05f, 0.40f, 0.15f, 0.05f, 0.20f, 0.05f, 0.05f
+       };
+       private Item[] worn = new Item[WEARING_COUNT];
+
+       /**
+        * Encode for network.
+        *
+        * @return
+        */
+       public String toEntity() {
+               StringBuilder sb = new StringBuilder();
+
+               for (int i = 0; i < worn.length; i++) {
+                       Item item = worn[i];
+                       if (item != null)
+                               sb.append(item.name).append('\n');
+                       else
+                               sb.append("none\n");
+               }
+               return sb.toString();
+       }
+
+       public Item getWorn(int where) {
+               return worn[where];
+       }
+
+       public boolean isWearing(String what) {
+               for (Item item : worn) {
+                       if (item != null && what.equalsIgnoreCase(item.name))
+                               return true;
+               }
+               return false;
+       }
+
+       /**
+        * Where a sepecific item
+        *
+        * @param where
+        * @param item
+        * @return
+        */
+       public Item wear(int where, Item item) {
+               Item old = worn[where];
+
+               worn[where] = item;
+               return old;
+       }
+
+       /**
+        * Unwear item at specific location
+        *
+        * @param where
+        * @return item if worn
+        */
+       public Item unwear(int where) {
+               Item old = worn[where];
+
+               worn[where] = null;
+               return old;
+       }
+
+       /**
+        * Unwear an item of a sepcific name
+        *
+        * @param name
+        * @return item if worn
+        */
+       public Item unwearByName(String name) {
+               for (int i = 0; i < worn.length; i++) {
+                       Item item = worn[i];
+
+                       if (item != null && name.equalsIgnoreCase(item.name)) {
+                               worn[i] = null;
+                               return item;
+                       }
+               }
+               return null;
+       }
+
+       /**
+        * Convert to wield type index
+        *
+        * @param where
+        * @return
+        */
+       public static int toIndex(String where) {
+               switch (where.toLowerCase()) {
+                       case "wielded":
+                               return WIELD;
+                       case "arms":
+                               return ARMS;
+                       case "legs":
+                               return LEGS;
+                       case "torso":
+                               return TORSO;
+                       case "waist":
+                               return WAIST;
+                       case "neck":
+                               return NECK;
+                       case "skull":
+                               return SKULL;
+                       case "eyes":
+                               return EYES;
+                       case "hands":
+                               return HANDS;
+               }
+               return -1;
+       }
+
+       public int armourCount() {
+               int count = 0;
+               for (int i = ARMS; i < worn.length; i++) {
+                       if (worn[i] != null)
+                               count++;
+               }
+               return count;
+       }
+
+       public int armourMod() {
+               int mod = 0;
+
+               for (int i = 0; i < worn.length; i++) {
+                       Item item = worn[i];
+
+                       if (item != null) {
+                               mod += ARMOUR_MOD[i] * item.intMod;
+                       }
+               }
+               return mod;
+       }
+
+       /**
+        * Damage the specified item if it exists
+        *
+        * @param damage
+        * @return the weapon if it was destroyed
+        */
+       public Item damageItem(int index, int damage) {
+               Item item = worn[index];
+
+               if (item != null && item.lngDurability != -1) {
+                       item.lngDurability -= damage;
+                       if (item.lngDurability < 0) {
+                               worn[index] = null;
+                               return item;
+                       }
+               }
+               return null;
+       }
+       // TODO: load/save functions here too?
+}
diff --git a/DuskServer/src/duskz/server/entity/Item.java b/DuskServer/src/duskz/server/entity/Item.java
new file mode 100644 (file)
index 0000000..b48901e
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, factory method/loader and script
+ * wrappers.
+ */
+package duskz.server.entity;
+
+import duskz.server.DuskEngine;
+import duskz.server.Script;
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+/*
+ All code copyright Tom Weingarten (captaint@home.com) 2000
+ Tom Weingarten makes no assurances as to the reliability or
+ functionality of this code. Use at your own risk. 
+
+ You are free to edit or redistribute this code or any portion
+ at your wish, under the condition that you do not edit or 
+ remove this license, and accompany it with all redistributions.
+ */
+//0-Ordinary Item
+//1-Weapon
+//2-Armor
+//3-Food
+//4-Drink
+/**
+ * An Item is an object that can be picked up, worn, and used. It can be of type
+ * Ordinary Item, Weapon, Armor, Food, or Drink.
+ *
+ * @author Tom Weingarten
+ */
+public class Item extends DuskObject {
+
+       public static final int ORDINARY = 0;
+       public static final int WEAPON = 1;
+       public static final int ARMOR = 2;
+       public static final int FOOD = 3;
+       public static final int DRINK = 4;
+       public static final int CONTAINER = 5;
+       private String strOnGetScript = null,
+                       strOnDropScript = null;
+       public String strOnUseScript = null,
+                       strOnWearScript = null,
+                       strOnUnWearScript = null,
+                       strOnOpenScript = null,
+                       strOnCloseScript = null,
+                       strOnAddItemScript = null,
+                       strOnRemoveItemScript = null;
+       public int intCost,
+                       intType = -1,
+                       intKind = -1,
+                       intMod,
+                       intUses = -1,
+                       intRange = 1;
+       int intImage;
+       int intWeight;                          // How much this object weighs
+       int intSize;                            // Amount of space this object takes up
+       int intCapacity;                        // How many items can this container hold
+       int intWeightLimit;                     // How much weight can this container hold
+       public long lngDurability = -1;
+       Item itmNext = null;
+
+       public Item(long lngID, String name) {
+               super(lngID, name);
+       }
+
+       boolean isOrdinaryItem() {
+               if (intType == ORDINARY) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isWeapon() {
+               if (intType == WEAPON) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isArmor() {
+               if (intType == ARMOR) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isFood() {
+               if (intType == FOOD) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isDrink() {
+               if (intType == DRINK) {
+                       return true;
+               }
+               return false;
+       }
+
+       boolean isContainer() {
+               if (intType == CONTAINER) {
+                       return true;
+               }
+               return false;
+       }
+
+       int range() {
+               return intRange;
+       }
+
+       @Override
+       public int getImage() {
+               return intImage;
+       }
+
+       @Override
+       public byte getType() {
+               return ITEM;
+       }
+
+       @Override
+       public int getEntityType() {
+               return 1;
+       }
+
+       /*
+        **     This method formats the Item for saving.
+        **     It generates a String that can later be passed
+        **     to fromString for populating a new Item.
+        */
+       public String toString() {
+               return "[strName:" + name
+                               + "::strDescription:" + description
+                               + "::strOnUseScript:" + strOnUseScript
+                               + "::strOnWearScript:" + strOnWearScript
+                               + "::strOnUnWearScript:" + strOnUnWearScript
+                               + "::strOnGetScript:" + strOnGetScript
+                               + "::strOnDropScript:" + strOnDropScript
+                               + "::intCost:" + intCost
+                               + "::intType:" + intType
+                               + "::intKind:" + intKind
+                               + "::intMod:" + intMod
+                               + "::intImage:" + intImage
+                               + "::intUses:" + intUses
+                               + "::intRange:" + intRange
+                               + "::lngDurability:" + lngDurability
+                               + "]";
+       }
+
+       public static Item getItem(long id, String inName) throws IOException {
+               Item itmStore = null;
+               RandomAccessFile rafItemDef = null;
+               String strStore = "Error reading file";
+               try {
+                       File fileTest = new File("defItems/" + inName.toLowerCase());
+                       if (!fileTest.exists()) {
+                               return null;
+                       }
+                       rafItemDef = new RandomAccessFile("defItems/" + inName.toLowerCase(), "r");
+                       //itmStore = new Item(this);
+                       itmStore = new Item(id, inName);
+                       itmStore.description = "a " + inName; //default description is name
+                       strStore = rafItemDef.readLine();
+                       while (!(strStore == null || strStore.equals("."))) {
+                               // FIXME: use enums
+                               if (strStore.equalsIgnoreCase("type")) {
+                                       strStore = rafItemDef.readLine();
+                                       if (strStore.equalsIgnoreCase("item")) {
+                                               itmStore.intType = 0;
+                                       } else if (strStore.equalsIgnoreCase("weapon")) {
+                                               itmStore.intType = 1;
+                                       } else if (strStore.equalsIgnoreCase("armor")) {
+                                               itmStore.intType = 2;
+                                       } else if (strStore.equalsIgnoreCase("food")) {
+                                               itmStore.intType = 3;
+                                       } else if (strStore.equalsIgnoreCase("drink")) {
+                                               itmStore.intType = 4;
+                                       }
+                               } else if (strStore.equalsIgnoreCase("kind")) {
+                                       strStore = rafItemDef.readLine();
+                                       if (strStore.equalsIgnoreCase("arms")) {
+                                               itmStore.intKind = 0;
+                                       } else if (strStore.equalsIgnoreCase("legs")) {
+                                               itmStore.intKind = 1;
+                                       } else if (strStore.equalsIgnoreCase("torso")) {
+                                               itmStore.intKind = 2;
+                                       } else if (strStore.equalsIgnoreCase("waist")) {
+                                               itmStore.intKind = 3;
+                                       } else if (strStore.equalsIgnoreCase("neck")) {
+                                               itmStore.intKind = 4;
+                                       } else if (strStore.equalsIgnoreCase("skull")) {
+                                               itmStore.intKind = 5;
+                                       } else if (strStore.equalsIgnoreCase("eyes")) {
+                                               itmStore.intKind = 6;
+                                       } else if (strStore.equalsIgnoreCase("hands")) {
+                                               itmStore.intKind = 7;
+                                       }
+                               } else if (strStore.equalsIgnoreCase("description")) {
+                                       itmStore.description = rafItemDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("cost")) {
+                                       itmStore.intCost = Integer.parseInt(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("durability")) {
+                                       itmStore.lngDurability = Long.parseLong(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("uses")) {
+                                       itmStore.intUses = Integer.parseInt(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("mod")) {
+                                       itmStore.intMod = Integer.parseInt(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("range")) {
+                                       itmStore.intRange = Integer.parseInt(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("image")) {
+                                       itmStore.intImage = Integer.parseInt(rafItemDef.readLine());
+                               } else if (strStore.equalsIgnoreCase("onuse")) {
+                                       itmStore.strOnUseScript = rafItemDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("onwear")) {
+                                       itmStore.strOnWearScript = rafItemDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("onunwear")) {
+                                       itmStore.strOnUnWearScript = rafItemDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("onget")) {
+                                       itmStore.strOnGetScript = rafItemDef.readLine();
+                               } else if (strStore.equalsIgnoreCase("ondrop")) {
+                                       itmStore.strOnDropScript = rafItemDef.readLine();
+                               }
+                               strStore = rafItemDef.readLine();
+                       }
+               } catch (NumberFormatException ex) {
+                       throw new IOException("Parsing: " + strStore, ex);
+               } catch (NullPointerException ex) {
+                       throw new IOException(ex);
+               } finally {
+                       if (rafItemDef != null) {
+                               rafItemDef.close();
+                       }
+               }
+               return itmStore;
+       }
+
+       public void onGetItem(DuskEngine eng, LivingThing trigger) {
+               if (strOnGetScript != null) {
+                       try {
+                               Script script = new Script("scripts/" + strOnGetScript, eng, false);
+                               script.varVariables.addVariable("trigger", trigger);
+                               script.varVariables.addVariable("itemname", name);
+                               script.varVariables.addVariable("mod", intMod);
+                               script.runScript();
+                               script.close();
+                       } catch (Exception e) {
+                               eng.log.printError("While running onGet script(" + strOnGetScript + ") for item \"" + name + "\"", e);
+                       }
+               }
+       }
+
+       public void onDropItem(DuskEngine eng, LivingThing trigger) {
+               if (strOnDropScript != null) {
+                       try {
+                               Script script = new Script("scripts/" + strOnDropScript, eng, false);
+                               script.varVariables.clearVariables();
+                               script.varVariables.addVariable("trigger", trigger);
+                               script.varVariables.addVariable("itemname", name);
+                               script.varVariables.addVariable("mod", intMod);
+                               script.runScript();
+                               script.close();
+                       } catch (Exception e) {
+                               eng.log.printError("While running onDrop script(" + strOnDropScript + ") for item \"" + name + "\"", e);
+                       }
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/LivingThing.java b/DuskServer/src/duskz/server/entity/LivingThing.java
new file mode 100644 (file)
index 0000000..4c5e9f6
--- /dev/null
@@ -0,0 +1,2914 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, lots of clean up and encapsulation
+ * and synchronisation fixes. Moved loader here.
+ */
+package duskz.server.entity;
+
+import duskz.server.Battle;
+import duskz.server.Commands;
+import duskz.server.Condition;
+import duskz.server.DuskEngine;
+import duskz.server.ItemList;
+import duskz.server.Log;
+import duskz.protocol.MessageType;
+import duskz.server.Script;
+import duskz.server.SpellGroup;
+import duskz.server.Variable;
+import duskz.server.entity.TileMap.MapData;
+import duskz.server.entity.TileMap.MoveData;
+import duskz.protocol.ServerMessage;
+import java.io.*;
+import java.net.Socket;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * LivingThing defines the base class for all moving objects. This includes
+ * Players, Pets, and Mobs.
+ *
+ * @author Tom Weingarten
+ */
+public class LivingThing extends DuskObject implements Runnable {
+
+       DuskEngine game;
+       final public LinkedBlockingQueue<ServerMessage> messageQueue = new LinkedBlockingQueue<>();
+       //StillWorking?
+       public boolean isWorking = true;
+       //Has the player finished loading yet?
+       public boolean isLoaded = false;
+       //Should the player be in who yet?
+       public boolean isReady = false;
+       //Can we save the player yet?
+       public boolean isSaveable = false;
+       //SHOULD we save the player yet?
+       public boolean isSaveNeeded = false;
+       //Is player in process of closing?
+       public boolean isClosing = false;
+       //Should we stop the thread?
+       public boolean isStopped = false;
+       //Should we process in-game commands after script is finished?
+       //(The script can change this to false to stop it from happening)
+       //(This allows scripts to short-circuit in-game commands)
+       public boolean isAlwaysCommands = true;
+       // File names for i/o
+       File file, backup;
+       //ID data
+       public String password,
+                       clan = "none",
+                       title = null,
+                       masterName = null;
+       //Group
+       LivingThing following = null,
+                       master = null,
+                       charmer = null;
+       //Stats
+       public int playerID, // uniquely identifies player for land ownership
+                       hp,
+                       maxhp,
+                       mp,
+                       maxmp,
+                       originalX,
+                       originalY,
+                       stre,
+                       inte,
+                       dext,
+                       cons,
+                       wisd,
+                       exp,
+                       hpbon = 0,
+                       mpbon = 0,
+                       strebon = 0,
+                       intebon = 0,
+                       dextbon = 0,
+                       consbon = 0,
+                       wisdbon = 0,
+                       dammodbon = 0,
+                       rangebon = 0,
+                       acbon = 0;
+       //Max values for stats
+       public int hp_limit = -1,
+                       mp_limit = -1,
+                       exp_limit = -1,
+                       stre_limit = 100,
+                       inte_limit = 100,
+                       dext_limit = 100,
+                       cons_limit = 100,
+                       wisd_limit = 100;
+       // FIXME: not public
+       public long cash;
+       // FIXME: not public
+       public long lastMessageStamp = 0;
+       //Status
+       // FIXME: accessor
+       public boolean isSleeping;
+       //Is this livingthing currently allowed to move?
+       public boolean isMoveable = true;
+       //For commands that need input...
+       boolean isHalted = false;
+       //Battle
+       // FIXME: accessor
+       public Battle battle = null;
+       public byte battleSide;
+       public long damageDone;
+       //Flags
+       // FIXME: accessor/helper
+       final public List<String> flags = new LinkedList<>();
+       //Conditions
+       final public List<Condition> conditions = new ArrayList<>();
+       //Skills
+       final HashMap<String, Ability> skillMap = new HashMap<>(2);
+       //Spells
+       final HashMap<String, Ability> spellMap = new HashMap<>(2);
+       // worn, FIXME: not public
+       public Equipment wornItems;
+       //Items
+       public ItemList itemList;
+       //Movement queue
+       final private LinkedList<String> moveQueue = new LinkedList<>();
+       //Entities (for optimized refresh)
+       private final HashMap<Long, DuskObject> nearEntities = new HashMap<>();
+       //Image id
+       int imageid;
+       // Image step for animation selection
+       public int imagestep;
+       //Race
+       public String race = null;
+       //Priveleges
+       public int privs = 0;
+       //Socket connection
+       private Socket socket;
+       // FIXME: not public
+       public DataInputStream instream;
+       // FIXME: not public
+       public DataOutputStream outstream;
+       public Thread connectionThread;
+       private SendThread sendThread;
+       //Prefs
+       public boolean audioon = true,
+                       coloron = true,
+                       popup = true,
+                       highlight = true,
+                       noFollow = false;
+       public int noChannel = 0;
+       //Timestamp of last save
+       long lastSaveStamp;
+       //List of players being ignored
+       final public List<String> ignoreList = new ArrayList<>();
+       //Type
+       /*
+        0=Player
+        1=Mob
+        2=Pet
+        */
+       byte Type;
+
+       public boolean isPlayer() {
+               if (Type == 0) {
+                       return true;
+               }
+               return false;
+       }
+
+       public boolean isMob() {
+               if (Type == 1) {
+                       return true;
+               }
+               return false;
+       }
+
+       public boolean isPet() {
+               if (Type == 2) {
+                       return true;
+               }
+               return false;
+       }
+
+       @Override
+       public byte getType() {
+               return LIVING_THING;
+       }
+
+       @Override
+       public int getImage() {
+               return imageid;
+       }
+
+       @Override
+       public int getEntityType() {
+               if (isMob() || isPet()) {
+                       return 4;
+               }
+               return 0;
+       }
+
+       /**
+        * Get IP address of user
+        *
+        * @return
+        */
+       public String getAddress() {
+               if (socket != null
+                               && socket.isConnected())
+                       return socket.getInetAddress().toString();
+               else
+                       return null;
+       }
+
+       @Override
+       public String toEntity() {
+               StringBuilder sb = new StringBuilder();
+               if (isSleeping) {
+                       sb.append("<sleeping>");
+               }
+               if (isPlayer() && !clan.equals("none")) {
+                       sb.append('<');
+                       sb.append(clan);
+                       sb.append('>');
+               }
+               if (isPet() && hp < 0) {
+                       sb.append("<wounded>");
+               }
+               for (String s : flags) {
+                       sb.append('<');
+                       sb.append(s);
+                       sb.append('>');
+               }
+               sb.append(name).append('\n');
+               sb.append(getEntityType()).append('\n');
+               sb.append(ID).append('\n');
+               sb.append(x).append('\n');
+               sb.append(y).append('\n');
+               sb.append(getImage()).append('\n');
+               if (isPlayer()) {
+                       sb.append(imagestep).append('\n');
+               }
+               return sb.toString();
+       }
+
+       @Override
+       public ServerMessage.EntityMessage toMessage(MessageType type) {
+               StringBuilder sb = new StringBuilder();
+               if (isSleeping) {
+                       sb.append("<sleeping>");
+               }
+               if (isPlayer() && !clan.equals("none")) {
+                       sb.append('<');
+                       sb.append(clan);
+                       sb.append('>');
+               }
+               if (isPet() && hp < 0) {
+                       sb.append("<wounded>");
+               }
+               for (String s : flags) {
+                       sb.append('<');
+                       sb.append(s);
+                       sb.append('>');
+               }
+               sb.append(name);
+               return new ServerMessage.EntityMessage(type, ID, sb.toString(),
+                               (byte) getEntityType(), (short) x, (short) y, (short) getImage(), (short) (isPlayer() ? imagestep : -1));
+       }
+
+       /**
+        * for extended classes
+        */
+       public LivingThing(long ID, String name) {
+               super(ID, name);
+       }
+
+       /**
+        * new Player
+        */
+       public LivingThing(Socket inSocket, DuskEngine inEngine) {
+               super(LIVING_THING, inEngine.getID());
+               try {
+                       sendThread = new SendThread();
+                       sendThread.start();
+                       Type = 0;
+                       game = inEngine;
+                       socket = inSocket;
+                       socket.setSoTimeout(600000); //10 minute timeout
+                       socket.setSoLinger(false, 0); //Do not linger on disconnect
+                       instream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
+                       outstream = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream()));
+                       game.log.printMessage(Log.INFO, socket.toString());
+                       battle = null;
+                       isSleeping = false;
+
+                       //
+                       // WTF is this stuff doing here??
+
+                       if (game.maxconnections != 0 && game.playersByName.size() >= game.maxconnections) {
+                               chatMessage("Sorry, the server has reached it's connection limit. Try again later.");
+                               send("Goodbye.\n" + (char) 0);
+                               Thread.sleep(1000);
+                               closeNosavePlayer();
+                               return;
+                       }
+                       // Game is shutting down
+                       if (game.blnShuttingDown) {
+                               chatMessage("Sorry, the server is not accepting new connections. It is either being shutdown or worked on.  Try again later.");
+                               send("Goodbye.\n" + (char) 0);
+                               Thread.sleep(1000);
+                               closeNosavePlayer();
+                               return;
+                       }
+                       if (!game.isGoodIP(socket.getInetAddress().toString())) {
+                               chatMessage("Connections from your machine are no longer being accepted.");
+                               send("Goodbye.\n" + (char) 0);
+                               Thread.sleep(1000);
+                               closeNosavePlayer();
+                               return;
+                       }
+                       // IP Filter FIXME: put on engine
+                       if (game.blnIPF) {
+                               for (LivingThing lt : game.playersByName.values()) {
+                                       String IP = lt.socket.getInetAddress().toString();
+                                       if (IP.equalsIgnoreCase(socket.getInetAddress().toString())) {
+                                               chatMessage("There's already a player connected from your IP address.");
+                                               send("Goodbye.\n" + (char) 0);
+                                               Thread.sleep(1000);
+                                               closeNosavePlayer();
+                                               return;
+                                       }
+                               }
+                       }
+                       // End IPF
+               } catch (Exception e) {
+                       game.log.printError("LivingThing():Creating player", e);
+               }
+       }
+
+       /**
+        * new Pet
+        */
+       public LivingThing(String strName, String strType, LivingThing master, DuskEngine inEngine) {
+               super(inEngine.getID(), strName);
+               try {
+                       Type = 2;
+                       game = inEngine;
+                       this.master = master;
+                       masterName = this.master.name.toLowerCase();
+                       charmer = this.master;
+                       x = this.master.x;
+                       y = this.master.y;
+                       battle = null;
+                       isSleeping = false;
+                       wornItems = new Equipment();
+                       itemList = new ItemList();
+
+                       //Load pet files
+
+                       String strStore = "";
+                       if (strType != null) {
+                               race = strType;
+                       }
+                       /*
+                        ** check to see if a pet exists
+                        */
+                       File filCheck;
+                       if (strName.equalsIgnoreCase("default")) {
+                               strStore = this.master.name.toLowerCase();
+                               filCheck = new File("pets/" + strStore);
+                               if (!filCheck.exists() && strType == null) {
+                                       closeNosavePlayer();
+                                       return;
+                               }
+                       }
+                       loadUserFile(new File("pets/default"));
+                       strStore = this.master.name.toLowerCase();
+                       File filPlayer = new File("pets/" + strStore);
+                       File filBackup = new File("pets/" + strStore + ".backup");
+                       /*
+                        ** Check for old style pet name
+                        ** (Only need to check if we already have a valid pet name)
+                        */
+                       if (!strName.equalsIgnoreCase("default")) {
+                               strStore = strName.toLowerCase();
+                               File filOldPet = new File("pets/" + strStore);
+                               File filOldBackup = new File("pets/" + strStore + ".backup");
+                               if (filOldPet.exists() && !filPlayer.exists()) {
+                                       filOldPet.renameTo(filPlayer);
+                                       filOldPet.delete();
+                               }
+                               if (filOldBackup.exists() && !filBackup.exists()) {
+                                       filOldBackup.renameTo(filBackup);
+                                       filOldBackup.delete();
+                               }
+                       }
+                       strStore = this.master.name.toLowerCase();
+                       int i = 0;
+                       if (filBackup.exists()) {
+                               if (filPlayer.length() > filBackup.length()) {
+                                       filCheck = new File("backup/" + strStore + ".possiblyDamaged");
+                                       while (filCheck.exists()) {
+                                               i++;
+                                               filCheck = new File("backup/" + strStore + ".possiblyDamaged." + i);
+                                       }
+                                       filBackup.renameTo(filCheck);
+                               } else if (filPlayer.length() < filBackup.length()) {
+                                       filCheck = new File("backup/" + strStore + ".possiblyDamaged");
+                                       while (filCheck.exists()) {
+                                               i++;
+                                               filCheck = new File("backup/" + strStore + ".possiblyDamaged." + i);
+                                       }
+                                       filPlayer.renameTo(filCheck);
+                                       filBackup.renameTo(new File("pets/" + strStore));
+                               }
+                       }
+                       strStore = this.master.name.toLowerCase();
+
+                       file = new File("pets", strStore);
+                       backup = new File("pets", strStore + ".backup");
+                       loadUserFile(file);
+                       if (race != null) {
+                               loadRaceFile(new File("defPets/" + race.toLowerCase()), true);
+                       }
+                       if (masterName == null) {
+                               masterName = this.master.name.toLowerCase();
+                       }
+                       //game.vctPets.addElement(this);
+                       isSaveable = true;
+               } catch (Exception e) {
+                       game.log.printError("LivingThing():Creating pet", e);
+                       close();
+               }
+       }
+
+       public LivingThing getFollowing() {
+               return following;
+       }
+
+       public LivingThing getMaster() {
+               return master;
+       }
+
+       public LivingThing getCharmer() {
+               return charmer;
+       }
+
+       public void setFollowing(LivingThing following) {
+               this.following = following;
+       }
+
+       public void setMaster(LivingThing master) {
+               this.master = master;
+       }
+
+       public void leaveBattle() {
+               battle = null;
+               battleSide = 0;
+               isMoveable = true;
+       }
+
+       public void enterBattle(Battle battle, int sideid) {
+//                     thnAdded.changeLocBypass(thnFront1.intLocX,thnFront1.intLocY);
+               isMoveable = false;
+               isSleeping = false;
+               this.battle = battle;
+               updateActions();
+               battleSide = (byte) sideid;
+       }
+
+       private void setAbility(Map<String, Ability> map, String name, int value) {
+               map.put(name.toLowerCase(), new Ability(value, name));
+       }
+
+       private int getAbility(Map<String, Ability> map, String name) {
+               Ability ability = map.get(name.toLowerCase());
+
+               return ability != null ? ability.getAbility() : 0;
+       }
+
+       public int getSkill(String name) {
+               return getAbility(skillMap, name);
+       }
+
+       public int getSpell(String name) {
+               return getAbility(spellMap, name);
+       }
+
+       /**
+        * Train a skill or spell.
+        *
+        * @param name
+        * @param add increment
+        * @return true if the skill/spell exists and was created/incremented
+        */
+       public boolean addToSkill(String name, int add) {
+               System.out.println("adding to skill " + name + " " + add);
+               String key = name.toLowerCase();
+               try {
+                       Ability skill = spellMap.get(key);
+                       if (skill == null) {
+                               File filCheck = new File("defSpellGroups/" + name);
+                               if (filCheck.exists()) {
+                                       setAbility(spellMap, name, add);
+                                       return true;
+                               }
+                               if ((skill = skillMap.get(name)) == null) {
+                                       setAbility(skillMap, name, add);
+                                       return true;
+                               }
+                       }
+                       return skill.train(add);
+               } catch (Exception e) {
+                       game.log.printError("addToSkill()", e);
+               }
+               return false;
+       }
+
+       public boolean setSkill(String name, int value) {
+               String key = name.toLowerCase();
+               if (value <= 0) {
+                       if (skillMap.remove(key) != null) {
+                               return true;
+                       }
+                       if (spellMap.remove(key) != null) {
+                               return true;
+                       }
+                       return false;
+               }
+               // TODO: try/catch not needed here
+               try {
+
+                       Ability skill = spellMap.get(key);
+                       if (skill == null) {
+                               File filCheck = new File("defSpellGroups/" + name);
+                               if (filCheck.exists()) {
+                                       setAbility(spellMap, name, value);
+                                       return true;
+                               }
+                               if ((skill = skillMap.get(name)) == null) {
+                                       setAbility(skillMap, name, value);
+                                       return true;
+                               }
+                       }
+                       skill.setAbility(value);
+                       return true;
+               } catch (Exception e) {
+                       game.log.printError("setSkill()", e);
+               }
+               return false;
+       }
+
+       int totalSkillValue() {
+               int total = 0;
+
+               for (Ability skill : skillMap.values())
+                       total += skill.getAbility();
+               for (Ability spell : spellMap.values())
+                       total += spell.getAbility();
+               return total;
+       }
+
+       public void loadUserFile(File path) throws FileNotFoundException, IOException {
+               String line;
+               try (RandomAccessFile file = new RandomAccessFile(path, "r")) {
+                       while (!((line = file.readLine()) == null || line.equals("."))) {
+                               try {
+                                       parseUserFile(file, line);
+                               } catch (NumberFormatException x) {
+                                       throw new IOException("Problem parsing user " + path + " on field " + line, x);
+                               }
+                       }
+               }
+       }
+
+       protected void parseWear(RandomAccessFile in, int where) throws IOException {
+               Item item = game.getItem(in.readLine());
+               if (item != null) {
+                       item.lngDurability = Long.parseLong(in.readLine());
+                       item.intUses = Integer.parseInt(in.readLine());
+                       wornItems.wear(where, item);
+                       onWear(item);
+               }
+       }
+
+       protected void parseUserFile(RandomAccessFile in, String type) throws IOException, NumberFormatException {
+               switch (type.toLowerCase()) {
+                       case "timestamp":
+                               lastSaveStamp = Long.parseLong(in.readLine());
+                               break;
+                       case "petname":
+                               name = in.readLine();
+                               break;
+                       case "master":
+                               masterName = in.readLine();
+                               break;
+                       case "skill":
+                               type = in.readLine();
+                               addToSkill(type, Byte.parseByte(in.readLine()));
+                               break;
+                       case "condition": {
+                               // FIXME: i/o to Condition
+                               Condition cndStore = game.getCondition(in.readLine());
+                               cndStore.ticksPast = Integer.parseInt(in.readLine());
+                               cndStore.duration = Integer.parseInt(in.readLine());
+                               if (cndStore.duration < -1) { // only necessary to repair
+                                       cndStore.duration = -1; // after bug fix, can go away
+                               }
+                               addCondition(cndStore);
+                               break;
+                       }
+                       case "item": {
+                               Item itmStore = game.getItem(in.readLine());
+                               if (itmStore != null) {
+                                       itemList.addElement(itmStore);
+                               }
+                               break;
+                       }
+                       case "item2": { //for compatibility. Will be replaced with item later
+                               Item itmStore = game.getItem(in.readLine());
+                               if (itmStore != null) {
+                                       itmStore.lngDurability = Long.parseLong(in.readLine());
+                                       itmStore.intUses = Integer.parseInt(in.readLine());
+                                       itemList.addElement(itmStore);
+                               }
+                               break;
+                       }
+                       case "privs":
+                               privs = Byte.parseByte(in.readLine());
+                               break;
+                       case "clan":
+                               clan = in.readLine();
+                               break;
+                       case "race":
+                               race = in.readLine();
+                               break;
+                       case "title":
+                               title = in.readLine();
+                               break;
+                       case "description":
+                               description = in.readLine();
+                               break;
+                       case "x":
+                               x = Integer.parseInt(in.readLine());
+                               break;
+                       case "y":
+                               y = Integer.parseInt(in.readLine());
+                               break;
+                       case "hp":
+                               hp = Integer.parseInt(in.readLine());
+                               break;
+                       case "maxhp":
+                               maxhp = Integer.parseInt(in.readLine());
+                               break;
+                       case "mp":
+                       case "sp":
+                               mp = Integer.parseInt(in.readLine());
+                               break;
+                       case "maxmp":
+                       case "maxsp":
+                               maxmp = Integer.parseInt(in.readLine());
+                               break;
+                       case "cash":
+                               cash = Integer.parseInt(in.readLine());
+                               break;
+                       case "exp":
+                               exp = Integer.parseInt(in.readLine());
+                               break;
+                       case "stre":
+                               stre = Integer.parseInt(in.readLine());
+                               break;
+                       case "inte":
+                               inte = Integer.parseInt(in.readLine());
+                               break;
+                       case "dext":
+                               dext = Integer.parseInt(in.readLine());
+                               break;
+                       case "cons":
+                               cons = Integer.parseInt(in.readLine());
+                               break;
+                       case "wisd":
+                               wisd = Integer.parseInt(in.readLine());
+                               break;
+                       case "image":
+                               imageid = Integer.parseInt(in.readLine());
+                               break;
+                       case "pet":
+                               if (!isPet()) {
+                                       following = new LivingThing(in.readLine(), null, this, game);
+                               }
+                               break;
+                       // FIXME: do i need these 'old' versions?
+                       case "wield":
+                               wornItems.wear(Equipment.WIELD, game.getItem(in.readLine()));
+                               break;
+                       case "arms":
+                               wornItems.wear(Equipment.ARMS, game.getItem(in.readLine()));
+                               break;
+                       case "legs":
+                               wornItems.wear(Equipment.LEGS, game.getItem(in.readLine()));
+                               break;
+                       case "torso":
+                               wornItems.wear(Equipment.TORSO, game.getItem(in.readLine()));
+                               break;
+                       case "waist":
+                               wornItems.wear(Equipment.WAIST, game.getItem(in.readLine()));
+                               break;
+                       case "neck":
+                               wornItems.wear(Equipment.NECK, game.getItem(in.readLine()));
+                               break;
+                       case "skull":
+                               wornItems.wear(Equipment.SKULL, game.getItem(in.readLine()));
+                               break;
+                       case "eyes":
+                               wornItems.wear(Equipment.EYES, game.getItem(in.readLine()));
+                               break;
+                       case "hands":
+                               wornItems.wear(Equipment.HANDS, game.getItem(in.readLine()));
+                               break;
+                       case "wield2":
+                               parseWear(in, Equipment.WIELD);
+                               break;
+                       case "arms2":
+                               parseWear(in, Equipment.ARMS);
+                               break;
+                       case "legs2":
+                               parseWear(in, Equipment.LEGS);
+                               break;
+                       case "torso2":
+                               parseWear(in, Equipment.TORSO);
+                               break;
+                       case "waist2":
+                               parseWear(in, Equipment.WAIST);
+                               break;
+                       case "neck2":
+                               parseWear(in, Equipment.NECK);
+                               break;
+                       case "skull2":
+                               parseWear(in, Equipment.SKULL);
+                               break;
+                       case "eyes2":
+                               parseWear(in, Equipment.EYES);
+                               break;
+                       case "hands2":
+                               parseWear(in, Equipment.HANDS);
+                               break;
+                       case "nofollow":
+                               noFollow = true;
+                               break;
+                       case "nopopup":
+                               popup = false;
+                               break;
+                       case "nochannel":
+                               noChannel = Integer.parseInt(in.readLine());
+                               break;
+                       case "audiooff":
+                               audioon = false;
+                               break;
+                       case "coloroff":
+                               coloron = false;
+                               break;
+               }
+               //      engGame.log.printError("parseUserFile():Parsing \"" + strStore + "\" from " + name + "'s file", e);
+       }
+
+       public void loadRaceFile(File path, boolean add) throws FileNotFoundException, IOException {
+               String line;
+               try (RandomAccessFile file = new RandomAccessFile(path, "r")) {
+                       while (!((line = file.readLine()) == null || line.equals("."))) {
+                               try {
+                                       parseRaceFile(file, line, add);
+                               } catch (NumberFormatException x) {
+                                       throw new IOException("Problem parsing race " + path + " on field " + line, x);
+                               }
+                       }
+               }
+       }
+
+       protected void parseRaceFile(RandomAccessFile file, String strStore, boolean add) {
+               int s = add ? 1 : -1;
+               try {
+                       switch (strStore) {
+                               case "hp":
+                                       hpbon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "mp":
+                                       mpbon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "stre":
+                                       strebon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "inte":
+                                       intebon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "dext":
+                                       dextbon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "cons":
+                                       consbon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "wisd":
+                                       wisdbon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "range":
+                                       rangebon += s * Integer.parseInt(file.readLine());
+                                       break;
+                               case "hp_limit":
+                                       hp_limit = add ? Integer.parseInt(file.readLine()) : -1;
+                                       break;
+                               case "mp_limit":
+                                       mp_limit = add ? Integer.parseInt(file.readLine()) : -1;
+                                       break;
+                               case "exp_limit":
+                                       exp_limit = add ? Integer.parseInt(file.readLine()) : -1;
+                                       break;
+                               case "stre_limit":
+                                       stre_limit = add ? Integer.parseInt(file.readLine()) : 100;
+                                       break;
+                               case "inte_limit":
+                                       inte_limit = add ? Integer.parseInt(file.readLine()) : 100;
+
+                                       break;
+                               case "dext_limit":
+                                       dext_limit = add ? Integer.parseInt(file.readLine()) : 100;
+                                       break;
+                               case "cons_limit":
+                                       cons_limit = add ? Integer.parseInt(file.readLine()) : 100;
+                                       break;
+                               case "wisd_limit":
+                                       wisd_limit = add ? Integer.parseInt(file.readLine()) : 100;
+                                       break;
+                               case "image":
+                                       imageid = Integer.parseInt(file.readLine());
+                                       break;
+                       }
+               } catch (Exception e) {
+                       game.log.printError("parseRaceFile():Parsing \"" + strStore + "\" from " + name + "'s race file", e);
+               }
+       }
+
+       void writePlayerFile(RandomAccessFile rafPlayerFile) throws IOException {
+               synchronized (rafPlayerFile) {
+                       rafPlayerFile.setLength(0);
+                       if (isPlayer()) {
+                               rafPlayerFile.writeBytes(password + "\n");
+                               rafPlayerFile.writeBytes("privs\n" + String.valueOf(privs) + "\n");
+                               if (title != null) {
+                                       rafPlayerFile.writeBytes("title\n" + title + "\n");
+                               }
+                               if (clan != null) {
+                                       rafPlayerFile.writeBytes("clan\n" + clan + "\n");
+                               } else {
+                                       rafPlayerFile.writeBytes("clan\nnone\n");
+                               }
+                               rafPlayerFile.writeBytes("x\n" + String.valueOf(x) + "\n");
+                               rafPlayerFile.writeBytes("y\n" + String.valueOf(y) + "\n");
+                               if (popup == false) {
+                                       rafPlayerFile.writeBytes("nopopup\n");
+                               }
+                               if (audioon == false) {
+                                       rafPlayerFile.writeBytes("audiooff\n");
+                               }
+                               if (coloron == false) {
+                                       rafPlayerFile.writeBytes("coloroff\n");
+                               }
+                               if (noFollow == true) {
+                                       rafPlayerFile.writeBytes("nofollow\n");
+                               }
+                               if (noChannel != 0) {
+                                       rafPlayerFile.writeBytes("nochannel\n" + noChannel + "\n");
+                               }
+                       }
+                       rafPlayerFile.writeBytes("race\n" + race + "\n");
+                       if (isPet()) {
+                               rafPlayerFile.writeBytes("petname\n" + name + "\n");
+                               rafPlayerFile.writeBytes("master\n" + masterName + "\n");
+                       }
+                       if (description != null) {
+                               rafPlayerFile.writeBytes("description\n" + description + "\n");
+                       }
+                       rafPlayerFile.writeBytes("exp\n" + String.valueOf(exp) + "\n");
+                       rafPlayerFile.writeBytes("hp\n" + String.valueOf(hp) + "\n");
+                       rafPlayerFile.writeBytes("maxhp\n" + String.valueOf(maxhp) + "\n");
+                       rafPlayerFile.writeBytes("mp\n" + String.valueOf(mp) + "\n");
+                       rafPlayerFile.writeBytes("maxmp\n" + String.valueOf(maxmp) + "\n");
+                       rafPlayerFile.writeBytes("cash\n" + String.valueOf(cash) + "\n");
+                       rafPlayerFile.writeBytes("stre\n" + String.valueOf(stre) + "\n");
+                       rafPlayerFile.writeBytes("inte\n" + String.valueOf(inte) + "\n");
+                       rafPlayerFile.writeBytes("dext\n" + String.valueOf(dext) + "\n");
+                       rafPlayerFile.writeBytes("cons\n" + String.valueOf(cons) + "\n");
+                       rafPlayerFile.writeBytes("wisd\n" + String.valueOf(wisd) + "\n");
+
+                       for (Ability skill : skillMap.values())
+                               rafPlayerFile.writeBytes("skill\n" + skill.name + "\n" + skill.getAbility() + "\n");
+                       for (Ability spell : spellMap.values())
+                               rafPlayerFile.writeBytes("skill\n" + spell.name + "\n" + spell.getAbility() + "\n");
+                       for (Condition cond : conditions) {
+                               rafPlayerFile.writeBytes("condition\n" + cond.name + "\n" + cond.ticksPast + "\n" + cond.duration + "\n");
+                       }
+                       for (int i = 0; i < Equipment.WEARING_COUNT; i++) {
+                               Item item = wornItems.getWorn(i);
+                               if (item != null) {
+                                       rafPlayerFile.writeBytes(Equipment.USER_NAMES[i] + "\n" + item.name + "\n" + item.lngDurability + "\n" + item.intUses + "\n");
+                               }
+                       }
+                       for (LinkedList<Item> list : itemList.values()) {
+                               for (Item item : list) {
+                                       rafPlayerFile.writeBytes("item2\n" + item.name + "\n" + item.lngDurability + "\n" + item.intUses + "\n");
+                               }
+                       }
+                       rafPlayerFile.writeBytes(".\n");//end of file
+               }
+       }
+
+       public void savePlayer() {
+               if (!isSaveNeeded) {
+                       /*
+                        ** User info has not changed significantly
+                        ** No need to save at this time.
+                        */
+                       return;
+               }
+               if (!isSaveable) {
+                       /*
+                        ** File is currently loading or saving and is not safe to
+                        ** save at this time.
+                        */
+                       return;
+               }
+               isSaveable = false;
+
+               String strStore = name.toLowerCase();
+               String strDirName = "users";
+               if (isPet()) {
+                       strStore = masterName;
+                       strDirName = "pets";
+               }
+
+               // This should work if it's going to, write out a whole file,
+               // and if that succeeds, copy it over
+
+               try (RandomAccessFile rafFile = new RandomAccessFile(backup, "rw")) {
+                       writePlayerFile(rafFile);
+               } catch (IOException x) {
+                       game.log.printMessage(Log.ERROR, "savePlayer():Saving primary file for " + backup + ", failed, aborting savePlayer");
+                       isSaveable = true;
+                       return;
+               }
+
+               try {
+                       Files.move(backup.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+               } catch (IOException ex) {
+                       game.log.printMessage(Log.ERROR, "savePlayer():Renaming primary file for " + file + ", failed, aborting savePlayer");
+               }
+
+               /*
+
+                boolean blnSaveSuccessful;
+                long lngFileLength = 0;
+                blnSaveSuccessful = writePlayerFile(rafFile);
+                try {
+                lngFileLength = rafFile.length();
+                } catch (Exception e) {
+                }
+
+                if (!blnSaveSuccessful || (lngFileLength < 100)) {
+                // Error saving file.  Close it, open it back up, and try again.
+                try {
+                rafFile.close();
+                } catch (Exception e) {
+                }
+                try {
+                rafFile = new RandomAccessFile(strDirName + "/" + strStore, "rw");
+                } catch (Exception e) {
+                }
+
+                blnSaveSuccessful = writePlayerFile(rafFile);
+
+                try {
+                lngFileLength = rafFile.length();
+                } catch (Exception e) {
+                }
+
+                if (!blnSaveSuccessful || (lngFileLength < 100)) {
+                engGame.log.printMessage(Log.ERROR, "savePlayer():Saving primary file for " + name + ", second try failed, aborting savePlayer");
+                blnCanSave = true;
+                return;
+                }
+                }
+
+                blnShouldSave = false;
+
+                blnSaveSuccessful = writePlayerFile(rafBackup);
+
+                try {
+                lngFileLength = rafBackup.length();
+                } catch (Exception e) {
+                }
+
+                if (!blnSaveSuccessful || (lngFileLength < 100)) {
+                // Error saving file.  Close it, open it back up, and try again.
+                try {
+                rafBackup.close();
+                } catch (Exception e) {
+                }
+                try {
+                rafBackup = new RandomAccessFile(strDirName + "/" + strStore + ".backup", "rw");
+                } catch (Exception e) {
+                }
+
+                blnSaveSuccessful = writePlayerFile(rafBackup);
+
+                try {
+                lngFileLength = rafBackup.length();
+                } catch (Exception e) {
+                }
+
+                if (!blnSaveSuccessful || (lngFileLength < 100)) {
+                engGame.log.printMessage(Log.ERROR, "savePlayer():Saving backup file for " + name + ", second try failed, aborting savePlayer");
+                blnCanSave = true;
+                return;
+                }
+                }
+                */
+               isSaveable = true;
+       }
+
+       public void close() {
+               if (name == null || name.equalsIgnoreCase("default")) {
+                       return;
+               }
+               if (isClosing) {
+                       /*
+                        ** Already closing elsewhere
+                        */
+                       return;
+               }
+               isClosing = true;
+               isWorking = false;
+               isSaveNeeded = true;
+               if (!conditions.isEmpty() && game.checkConditionList.contains(this)) {
+                       game.checkConditionList.remove(this);
+               }
+               removeFromGroup();
+               try {
+                       game.removeDuskObject(this);
+                       if (isPlayer()) {
+                               try {
+                                       synchronized (game.scrOnLogOut) {
+                                               if (isSaveable) {
+                                                       game.scrOnLogOut.varVariables.clearVariables();
+                                                       game.scrOnLogOut.varVariables.addVariable("trigger", this);
+                                                       game.scrOnLogOut.runScript();
+                                               }
+                                       }
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       outstream.writeBytes((char) 3 + "Goodbye.\n" + (char) 0);
+                               } catch (Exception e) {
+                               }
+                               synchronized (game.playersByName) {
+                                       game.playersByName.remove(name.toLowerCase());
+                               }
+                               try {
+                                       savePlayer();
+                               } catch (Exception e) {
+                               }
+                               isSaveable = false;
+                               //try {
+                               //      rafFile.close();
+                               //      rafBackup.close();
+                               //} catch (Exception e) {
+                               //}
+                               try {
+                                       if (following != null && following.isPet()) {
+                                               following.close();
+                                       }
+                                       for (LivingThing pet : game.petList) {
+                                               if (pet.master == this) {
+                                                       pet.close();
+                                                       break;
+                                               }
+                                       }
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       instream.close();
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       outstream.close();
+                               } catch (Exception e) {
+                               }
+                               if (!(hasCondition("invis") && (privs > 2))) {
+                                       game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " has logged out");
+                                       game.chatMessage(name + " has logged out.", name);
+                               } else {
+                                       game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " has logged out hidden from players");
+                               }
+                               try {
+                                       socket.close();
+                               } catch (Exception e) {
+                               }
+                               isStopped = true;
+                       } else if (isMob()) {
+                               //try {
+                               //      rafFile.close();
+                               //      rafBackup.close();
+                               //} catch (Exception e) {
+                               //}
+                               //game.vctMobs.remove(this);
+                       } else if (isPet()) {
+                               //game.vctPets.removeElement(this);
+                               savePlayer();
+                               //try {
+                               //      rafFile.close();
+                               //      rafBackup.close();
+                               //} catch (Exception e) {
+                               //}
+                       }
+               } catch (Exception e) {
+                       game.log.printError("close():While closing " + name, e);
+               }
+       }
+
+       public void closeNoMsgPlayer() {
+               // Disabled this check... if this is called, the player needs to be closed.
+               //      if (blnIsClosing)
+               //      {
+               //              /*
+               //              ** Already closing elsewhere
+               //              */
+               //              return;
+               //      }
+               isClosing = true;
+               isWorking = false;
+               removeFromGroup();
+               if (conditions.size() != 0) {
+                       game.checkConditionList.remove(this);
+               }
+               game.removeDuskObject(this);
+               game.playersByName.remove(name.toLowerCase());
+               try {
+                       socket.shutdownInput();
+               } catch (Exception e) {
+               }
+               try {
+                       socket.shutdownOutput();
+               } catch (Exception e) {
+               }
+               try {
+                       instream.close();
+               } catch (Exception e) {
+               }
+               savePlayer();
+               //try {
+               //      rafFile.close();
+               //      rafBackup.close();
+               //} catch (Exception e) {
+               //}
+               if (following != null && following.isPet()) {
+                       following.close();
+               }
+               try {
+                       outstream.close();
+               } catch (Exception e) {
+               }
+               isStopped = true;
+               game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " has logged out");
+               game.chatMessage(name + " has logged out.", name);
+               try {
+                       socket.close();
+               } catch (Exception e) {
+               }
+               name = null;
+       }
+
+       void closeNosavePlayer() {
+               if (name == null || name.equalsIgnoreCase("default")) {
+                       isStopped = true;
+                       try {
+                               instream.close();
+                       } catch (Exception e) {
+                       }
+                       try {
+                               socket.close();
+                       } catch (Exception e) {
+                       }
+                       try {
+                               outstream.close();
+                       } catch (Exception e) {
+                       }
+                       return;
+               }
+               if (isClosing) {
+                       /*
+                        ** Already closing elsewhere
+                        */
+                       return;
+               }
+               isClosing = true;
+               isWorking = false;
+               isSaveable = false;
+               isSaveNeeded = false;
+               if (!conditions.isEmpty() && game.checkConditionList.contains(this)) {
+                       game.checkConditionList.remove(this);
+               }
+               removeFromGroup();
+               try {
+                       game.removeDuskObject(this);
+                       if (isPlayer()) {
+                               try {
+                                       synchronized (game.scrOnLogOut) {
+                                               //engGame.scrOnLogOut.varVariables.clearVariables();
+                                               //engGame.scrOnLogOut.varVariables.addVariable("trigger",this);
+                                               //engGame.scrOnLogOut.runScript();
+                                       }
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       outstream.writeBytes((char) 3 + "Goodbye.\n" + (char) 0);
+                               } catch (Exception e) {
+                               }
+                               //try {
+                               //      rafFile.close();
+                               //      rafBackup.close();
+                               //} catch (Exception e) {
+                               //}
+                               game.playersByName.remove(name.toLowerCase());
+                               try {
+                                       instream.close();
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       outstream.close();
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       socket.close();
+                               } catch (Exception e) {
+                               }
+                               isStopped = true;
+                       } else if (isMob()) {
+                               //game.vctMobs.remove(this);
+                       } else if (isPet()) {
+                               //game.vctPets.removeElement(this);
+                               //try {
+                               //      rafFile.close();
+                               //      rafBackup.close();
+                               //} catch (Exception e) {
+                               //}
+                       }
+               } catch (Exception e) {
+                       game.log.printError("closeNosavePlayer():While closing " + name, e);
+               }
+       }
+
+       public void updateFlag(long ID, int Value) {
+               send((char) 29 + "" + ID + "\n" + Value + "\n");
+       }
+
+       public void clearFlags() {
+               send((char) 30 + "");
+       }
+
+       public boolean hasPendingMoves() {
+               synchronized (moveQueue) {
+                       return !moveQueue.isEmpty();
+               }
+       }
+
+       /**
+        * Clear any pending moves and queue a new move direction
+        *
+        * @param dir n/s/e/w
+        * @return true if move is possible
+        */
+       public boolean moveAfterClear(String dir) {
+               if (getMaster() != null) {
+                       if (!isPet() || getMaster().getFollowing() == this) {
+                               return false;
+                       }
+               }
+               synchronized (moveQueue) {
+                       moveQueue.clear();
+                       moveQueue.add(dir);
+               }
+               return true;
+       }
+
+       public void clearMoveQueue() {
+               synchronized (moveQueue) {
+                       moveQueue.clear();
+               }
+       }
+
+       /**
+        * Process one queued move
+        */
+       public void moveTick() {
+               synchronized (moveQueue) {
+                       if (moveQueue.isEmpty())
+                               return;
+
+                       String dir = moveQueue.removeFirst();
+
+                       if (dir != null) {
+                               switch (dir.charAt(0)) {
+                                       case 'n':
+                                               moveN();
+                                               break;
+                                       case 's':
+                                               moveS();
+                                               break;
+                                       case 'w':
+                                               moveW();
+                                               break;
+                                       case 'e':
+                                               moveE();
+                                               break;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * Send this to a specific destination.
+        *
+        * This is a completely new implementation using the map
+        *
+        * @param destX
+        * @param destY
+        * @param goon If true, go to exact location, otherwise only next to it
+        * @return
+        */
+       public String goTo(int destX, int destY, boolean goon) {
+               if (master != null) {
+                       if (!isPet() || master.following == this) {
+                               return "You can't move while you're following someone.";
+                       }
+               }
+               if (goon && !game.canMoveTo(destX, destY, this)) {
+                       return "You can't move onto that location.";
+               }
+               if (Math.abs(destX - x) > game.viewrange || Math.abs(destY - y) > game.viewrange) {
+                       return null;
+               }
+               synchronized (moveQueue) {
+                       moveQueue.clear();
+
+                       TileMap.MoveListener ml = new TileMap.MoveListener() {
+                               @Override
+                               public boolean canMoveto(MapData md) {
+                                       return game.canMoveTo(md.x, md.y, LivingThing.this);
+                               }
+                       };
+                       int mflags = goon ? 0 : TileMap.SKIP_END;
+
+                       for (MoveData md : game.map.move(x, y, destX, destY, mflags, ml)) {
+                               moveQueue.add(md.direction);
+                       }
+               }
+               return null;
+       }
+
+       // FIXME: should probably be in DuskEngine
+       protected synchronized void moveTo(int newLocX, int newLocY, MessageType dir, int intNewStep) {
+               if (privs < 5 && (newLocX >= (game.map.getCols() - 1)
+                               || newLocY >= (game.map.getRows() - 1)
+                               || newLocX < 0
+                               || newLocY < 0)) {
+                       return;
+               }
+               // Movement during combat is disallowed here
+               // need to check min range in the battle and see if anything is at 1 with this livingthing
+//             if (privs>1 || (batBattle == null && !blnSleep && engGame.canMoveTo(newLocX,newLocY,this)))
+               if (privs > 1 || (isMoveable && !isSleeping && game.canMoveTo(newLocX, newLocY, this))) {
+                       if (isMob()) {
+                               int maxY = originalY + game.viewrange;
+                               int minY = originalY - game.viewrange;
+                               int maxX = originalX + game.viewrange;
+                               int minX = originalX - game.viewrange;
+                               if ((newLocY > maxY) || (newLocY < minY) || (newLocX > maxX) || (newLocX < minX)) {
+                                       return;
+                               }
+                       }
+               } else {
+                       return;
+               }
+               int oldLocX = x;
+               int oldLocY = y;
+               // Move it from cell to cell
+               game.moveDuskObject(this, newLocX, newLocY, dir);
+               try {
+                       imagestep = intNewStep;
+                       if (isPlayer()) {
+                               if (game.overMerchant(oldLocX, oldLocY) != null) {
+                                       offMerchant();
+                               }
+                               if (game.overPlayerMerchant(oldLocX, oldLocY) != null) {
+                                       offMerchant();
+                               }
+                               updateMap();
+                       }
+                       Script scrStore;
+                       try {
+                               scrStore = (Script) game.tileAction.get((int) game.map.getTile(x, y));
+                               synchronized (scrStore) {
+                                       scrStore.varVariables.clearVariables();
+                                       scrStore.varVariables.addVariable("trigger", this);
+                                       scrStore.runScript();
+                               }
+                       } catch (Exception e) {
+                       }
+                       Script.exec("defMoveActions/" + x + "_" + y, game, this);
+
+                       //move follower
+                       if (following != null) {
+                               //don't move follower if leader has moved onto follower's tile
+                               if ((following.x == newLocX) && (following.y == newLocY)) {
+                                       return;
+                               }
+                               if (Math.abs(following.x - oldLocX) + Math.abs(following.y - oldLocY) > 1) {
+                                       if (following.isPet()) {
+                                               if (following.following != null) {
+                                                       chatMessage(following.following.name + " is no longer following you.");
+                                                       following.following.chatMessage("You are no longer following " + name + ".");
+                                                       following.following.master = null;
+                                                       following.following = null;
+                                               }
+                                               following.changeLocBypass(oldLocX, oldLocY);
+                                       } else {
+                                               chatMessage(following.name + " is no longer following you.");
+                                               following.chatMessage("You are no longer following " + name + ".");
+                                               following.master = null;
+                                               following = null;
+                                       }
+                               } else if (following.y > oldLocY) {
+                                       following.moveN();
+                               } else if (following.y < oldLocY) {
+                                       following.moveS();
+                               } else if (following.x > oldLocX) {
+                                       following.moveW();
+                               } else if (following.x < oldLocX) {
+                                       following.moveE();
+                               }
+                       }
+                       if (isPlayer()) {
+                               game.refreshEntities(this);
+                       }
+                       //game.removeIfCanNoLongerSee(this);
+               } catch (Exception e) {
+                       game.log.printError("moveTo()", e);
+               }
+       }
+
+       public void moveN() {
+               moveTo(x, y - 1, MessageType.MoveNorth, 0);
+       }
+
+       public void moveS() {
+               moveTo(x, y + 1, MessageType.MoveSouth, 2);
+       }
+
+       public void moveW() {
+               moveTo(x - 1, y, MessageType.MoveWest, 4);
+       }
+
+       public void moveE() {
+               moveTo(x + 1, y, MessageType.MoveEast, 6);
+       }
+
+       public DuskObject removeEntity(long id) {
+               synchronized (nearEntities) {
+                       DuskObject o = nearEntities.remove(id);
+
+                       if (o != null) {
+                               System.out.println("Removing client entity " + id + " from " + name);
+                               send(MessageType.RemoveEntity, id + "\n");
+                       }
+                       return o;
+               }
+       }
+
+       public boolean nearEntity(long id) {
+               synchronized (nearEntities) {
+                       return nearEntities.containsKey(id);
+               }
+       }
+
+       public void addEntity(DuskObject ent) {
+               synchronized (nearEntities) {
+                       if (nearEntities.containsKey(ent.ID))
+                               return;
+
+                       System.out.println("Adding client entity " + ent.ID + " " + ent.name + " to " + name);
+
+                       nearEntities.put(ent.ID, ent);
+               }
+
+               // Only sent to player if they can see it?
+               if (!ent.isLivingThing()
+                               || game.canSeeLivingThing(this, (LivingThing) ent)) {
+                       System.out.println("Adding entity " + ent.name + " to " + name);
+                       //send(MessageType.AddEntity, ent.toEntity());
+                       send(ent.toMessage(MessageType.AddEntity));
+               } else {
+                       System.out.println("Not adding entity " + ent.name + " to " + name);
+               }
+       }
+
+       /**
+        * Set a new set of near-entities
+        *
+        * @param ent
+        */
+       public void setEntities(List<DuskObject> newEntities) {
+               HashMap<Long, DuskObject> left = (HashMap<Long, DuskObject>) nearEntities.clone();
+
+               if (false) {
+                       System.out.println("setting entities on " + name);
+                       for (DuskObject d : left.values()) {
+                               System.out.println(" - " + d.ID + " " + d.name);
+                       }
+                       for (DuskObject d : newEntities) {
+                               System.out.println(" + " + d.ID + " " + d.name);
+                       }
+               }
+
+               for (DuskObject o : newEntities) {
+                       if (left.containsKey(o.ID)) {
+                               // Have this already, do nothing
+                               left.remove(o.ID);
+                       } else {
+                               // This is a new one
+                               //nearEntities.put(o.ID, o);
+                               game.addEntity(o);
+                       }
+               }
+               // anything left over must be removed
+               for (long id : left.keySet()) {
+                       removeEntity(id);
+               }
+       }
+
+       public void changeLoc(int newLocX, int newLocY) {
+               if (privs > 1 || (battle == null && !isSleeping && game.canMoveTo(newLocX, newLocY, this))) {
+                       if (isMob()) {
+                               if (!(Math.abs(originalX - newLocX) < game.viewrange && Math.abs(originalY - newLocY) < game.viewrange)) {
+                                       return;
+                               }
+                       }
+                       changeLocBypass(newLocX, newLocY);
+               }
+       }
+
+       synchronized public void changeLocBypass(int newLocX, int newLocY) {
+               int oldLocX = x;
+               int oldLocY = y;
+               game.removeDuskObject(this);
+               x = newLocX;
+               y = newLocY;
+               try {
+                       if (isPlayer()) {
+                               updateMap();
+                               if (game.overMerchant(oldLocX, oldLocY) != null) {
+                                       offMerchant();
+                               }
+                               if (game.overPlayerMerchant(oldLocX, oldLocY) != null) {
+                                       offMerchant();
+                               }
+                       }
+                       //update entity:
+                       if (isWorking) {
+                               game.addDuskObject(this);
+                       }
+                       Script scrStore;
+                       try {
+                               scrStore = (Script) game.tileAction.get((int) game.map.getTile(newLocX, newLocY));
+                               synchronized (scrStore) {
+                                       scrStore.varVariables.clearVariables();
+                                       scrStore.varVariables.addVariable("trigger", this);
+                                       scrStore.runScript();
+                               }
+                       } catch (Exception e) {
+                       }
+                       Script.exec("defMoveActions/" + newLocX + "_" + newLocY, game, this);
+                       if (following != null) {
+                               following.changeLocBypass(oldLocX, oldLocY);
+                       }
+                       if (isPlayer()) {
+                               game.refreshEntities(this);
+                       }
+               } catch (Exception e) {
+                       game.log.printError("changeLocBypass():" + name + " disconnected", e);
+                       isStopped = true;
+               }
+       }
+
+       public void updateMap() {
+               /*
+                StringBuilder sb = new StringBuilder();
+                //update map:
+
+                sb.append(x).append("\n");
+                sb.append(y).append("\n");
+
+                int r = game.viewrange;
+                for (int mx = x - r; mx <= x + r; mx++) {
+                for (int my = y - r; my <= y + r; my++) {
+                if (game.map.inside(mx, my))
+                sb.append(game.map.getTile(mx, my)).append("\n");
+                else
+                sb.append("0\n");
+                }
+                }
+
+                send(MessageType.UpdateLocMap, sb.toString());*/
+
+               int r = game.viewrange;
+
+               short[] tiles = new short[(r * 2 + 1) * (r * 2 + 1)];
+               int i = 0;
+               //System.out.printf("map at %d,%d\n", x, y);
+               for (int my = y - r; my <= y + r; my++) {
+                       for (int mx = x - r; mx <= x + r; mx++) {
+                               tiles[i++] = game.map.inside(mx, my) ? game.map.getTile(mx, my) : 0;
+                               //System.out.printf("%s%3d", game.map.inside(mx, my) ? " " : "*", tiles[i-1]);
+                       }
+                       //System.out.println("\n");
+               }
+
+               send(ServerMessage.mapMessage(x, y, tiles));
+       }
+
+       public void chatMessage(String inMessage) {
+               if (inMessage == null) {
+                       return;
+               }
+               if (isPlayer()) {
+                       send(MessageType.Chat, inMessage + "\n");
+               }
+               if (charmer != null) {
+                       charmer.chatMessage("From " + name + ": " + inMessage);
+                       return;
+               }
+       }
+
+       public void chatMessage(int red, int green, int blue, String inMessage) {
+               if (inMessage == null) {
+                       return;
+               }
+               if (isPlayer()) {
+                       if (!coloron) {
+                               chatMessage(inMessage);
+                               return;
+                       }
+                       String strResult = "" + (char) 23;
+                       strResult += red + "\n" + green + "\n" + blue + "\n" + inMessage + "\n";
+                       send(strResult);
+               }
+               if (charmer != null) {
+                       charmer.chatMessage(red, green, blue, "From " + name + ": " + inMessage);
+                       return;
+               }
+       }
+
+       public int getCharacterPoints() {
+               int result = wisd
+                               + inte
+                               + stre
+                               + dext
+                               + cons
+                               + ((maxhp) / 10)
+                               + ((maxmp) / 10)
+                               + totalSkillValue();
+               return result;
+       }
+
+       public int getTotalPoints() {
+               int result = getCharacterPoints()
+                               + getArmorMod()
+                               + (getDamMod() - 100);
+               return result;
+       }
+
+       public Item getItem(String strStore) {
+               // Check worn items by location, TBH not really sure of the point of this
+               int where = Equipment.toIndex(strStore);
+               if (where != -1) {
+                       Item item = wornItems.getWorn(where);
+                       if (item != null)
+                               return item;
+               }
+
+               int i,
+                               intNumber = 1;
+               i = strStore.indexOf('.');
+               if (i != -1) {
+                       try {
+                               intNumber = Integer.parseInt(strStore.substring(0, i));
+                               strStore = strStore.substring(i + 1, strStore.length());
+                       } catch (NumberFormatException e) {
+                               intNumber = 1;
+                       }
+               }
+               Item itmStore;
+               LinkedList<Item> qStore;
+               qStore = itemList.get(strStore);
+               if (qStore != null) {
+                       if (qStore.size() >= intNumber) {
+                               itmStore = (Item) qStore.element();
+                               return itmStore;
+                       }
+               }
+               return null;
+       }
+
+       public Item getItemAndRemove(String strStore) {
+               int i,
+                               intNumber = 1;
+               i = strStore.indexOf(".");
+               if (i != -1) {
+                       try {
+                               intNumber = Integer.parseInt(strStore.substring(0, i));
+                               strStore = strStore.substring(i + 1, strStore.length());
+                       } catch (NumberFormatException e) {
+                               intNumber = 1;
+                       }
+               }
+               if (intNumber == 0) {
+                       return null;
+               }
+               Item itmStore;
+               Item itmFound = null;
+               LinkedList<Item> qStore;
+               qStore = itemList.get(strStore);
+               if (qStore != null) {
+                       if (!qStore.isEmpty()) {
+                               itmStore = (Item) qStore.element();
+                               itmFound = itmStore;
+                               while (intNumber != 0 && itmStore != null) {
+                                       qStore.pop();
+                                       intNumber--;
+                               }
+                               if (qStore.size() < 1) {
+                                       itemList.removeElement(strStore);
+                               }
+                       } else {
+                               itemList.removeElement(strStore);
+                       }
+               }
+               return itmFound;
+       }
+
+       public int getArmorMod() {
+               return wornItems.armourMod();
+       }
+
+       public int getArmorModWithBonus() {
+               return getArmorMod() + ((dext + dextbon) / 10) + acbon;
+       }
+
+       public int getDamMod() {
+               Item item = wornItems.getWorn(Equipment.WIELD);
+               if (item != null)
+                       return item.intMod;
+               return 100;
+       }
+
+       public int getDamModWithBonus() {
+               return getDamMod() + dammodbon;
+       }
+
+       public int getRange() {
+               Item item = wornItems.getWorn(Equipment.WIELD);
+
+               if (item == null) {
+                       return 1;
+               }
+               return item.range();
+       }
+
+       public int getRangeWithBonus() {
+               return getRange() + rangebon;
+       }
+
+       public void weaponDam(int damage) {
+               if (isMob()) //Mobs weapons are invincible
+               {
+                       return;
+               }
+
+               Item item = wornItems.damageItem(Equipment.WIELD, damage);
+               if (item != null) {
+                       chatMessage("Your " + item.name + " breaks.");
+                       onUnwear(item);
+                       if (isPlayer()) {
+                               updateEquipment();
+                               updateStats();
+                       }
+               }
+       }
+
+       public void armorDam(int damage) {
+               if (isMob()) //Mobs armor is invincible
+               {
+                       return;
+               }
+               int armour = wornItems.armourCount();
+               if (armour == 0) {
+                       return;
+               }
+
+               for (int i = Equipment.ARMS; i < Equipment.WEARING_COUNT; i++) {
+                       Item item = wornItems.damageItem(Equipment.WIELD, damage);
+                       if (item != null) {
+                               chatMessage("Your " + item.name + " breaks.");
+                               onUnwear(item);
+                               updateStats();
+                               updateEquipment();
+                       }
+               }
+       }
+
+       public void useItem(String strStore, int mustBeType) {
+               String strStore2 = null;
+               int i2 = 0;
+               if (strStore.startsWith("\"")) {
+                       char c, c2;
+
+                       strStore2 = "";
+                       i2 = 1;
+                       try {
+                               while (true) {
+                                       c = strStore.charAt(i2);
+                                       if (c == '\\') {
+                                               c2 = strStore.charAt(i2 + 1);
+                                               strStore2 += c2;
+                                       } else if (c == '\"') {
+                                               i2++;
+                                               break;
+                                       } else {
+                                               strStore2 += c;
+                                       }
+                                       i2++;
+                               }
+                       } catch (Exception e) {
+                               chatMessage("You don't have that.");
+                               return;
+                       }
+               } else {
+                       i2 = strStore.indexOf(" ");
+                       if (i2 == -1) {
+                               strStore2 = strStore;
+                               i2 = strStore.length();
+                       } else {
+                               strStore2 = strStore.substring(0, i2);
+                       }
+               }
+               if (strStore.length() > i2 + 1) {
+                       strStore = strStore.substring(i2 + 1);
+               }
+               Item itmStore = getItem(strStore2);
+               if (itmStore == null) {
+                       chatMessage("You don't have that.");
+                       return;
+               }
+               if (itmStore.strOnUseScript == null) {
+                       chatMessage("That has no use.");
+                       return;
+               }
+               if (mustBeType != -1 && itmStore.intType != mustBeType) {
+                       chatMessage("You can't use that like that.");
+                       return;
+               }
+               if (itmStore.intUses == 0) {
+                       chatMessage("That item is used up.");
+                       return;
+               }
+               try {
+                       Script scrStore = new Script("scripts/" + itmStore.strOnUseScript, game, false);
+//                     synchronized(scrStore)
+//                     {
+                       scrStore.varVariables.addVariable("trigger", this);
+                       scrStore.varVariables.addVariable("itemname", itmStore.name);
+                       scrStore.varVariables.addVariable("mod", itmStore.intMod);
+                       scrStore.runScript();
+                       scrStore.close();
+//                     }
+               } catch (Exception e) {
+                       chatMessage("That has no use.");
+                       return;
+               }
+               itmStore.intUses--;
+       }
+
+       public void castSpell(String spell) {
+               String strStore = "",
+                               strStore2 = "";
+               int intStore,
+                               intStore2;
+               LivingThing target = null;
+               // FIXME: de-quote and/or command parser
+               int i2 = 0;
+               if (spell.startsWith("\"")) {
+                       char c, c2;
+                       i2 = 1;
+                       try {
+                               while (true) {
+                                       c = spell.charAt(i2);
+                                       i2++;
+                                       if (c == '\"') {
+                                               break;
+                                       }
+                                       if (c == '\\') {
+                                               c2 = spell.charAt(i2);
+                                               strStore2 += c2;
+                                       } else {
+                                               strStore2 += c;
+                                       }
+                               }
+                       } catch (Exception e) {
+                               chatMessage("You don't know that spell.");
+                       }
+               } else {
+                       i2 = spell.indexOf(" ");
+                       if (i2 == -1) {
+                               strStore2 = spell;
+                               i2 = spell.length();
+                       } else {
+                               strStore2 = spell.substring(0, i2);
+                       }
+               }
+               if (spell.length() > i2 + 1) {
+                       spell = spell.substring(i2 + 1);
+               } else {
+                       spell = null;
+               }
+               try {
+                       try (RandomAccessFile rafSpell = new RandomAccessFile("defSpells/" + strStore2.toLowerCase(), "r")) {
+                               strStore = rafSpell.readLine();
+                       } catch (FileNotFoundException x) {
+                               chatMessage("You don't know that spell.");
+                               return;
+                       }
+                       SpellGroup grpStore = game.getSpellGroup(strStore);
+                       intStore = getSpell(strStore);
+                       intStore2 = grpStore.getSpellNumber(strStore2);
+                       if (grpStore == null) {
+                               chatMessage("You don't know that spell.");
+                               return;
+                       }
+                       // FIXME: reorder this so the script is only created after the checks
+                       Script scrSpell;
+                       try {
+                               scrSpell = new Script("defSpellGroups/" + intStore2 + " " + strStore.toLowerCase(), game, false);
+                       } catch (Exception e) {
+                               chatMessage("You don't know that spell.");
+                               return;
+                       }
+                       if (intStore2 != 0) //change number to percent
+                       {
+                               intStore2 = (100 * intStore2) / (grpStore.vctSpells.size() - 1);
+                       }
+                       if (intStore == 0 || intStore < intStore2) {
+                               chatMessage("You don't know that spell.");
+                               scrSpell.close();
+                               return;
+                       }
+                       intStore2 = (110 - (intStore - intStore2)) / 2; //change percent to mp cost
+                       if (intStore2 > mp) {
+                               chatMessage("You don't have enough mp to cast that spell.");
+                               scrSpell.close();
+                               return;
+                       }
+                       mp -= intStore2;
+                       scrSpell.varVariables.addVariable("caster", this);
+                       if (spell == null) {
+                               scrSpell.runScript();
+                       } else {
+                               scrSpell.runScript(spell);
+                       }
+                       scrSpell.close();
+                       if (isPlayer()) {
+                               updateInfo();
+                       }
+               } catch (Exception e) {
+                       game.log.printError("castSpell()", e);
+               }
+       }
+
+       public boolean isWearing(String name) {
+               return wornItems.isWearing(name);
+       }
+
+       private void unwear(Item old) {
+               if (old != null) {
+                       itemList.addElement(old);
+                       onUnwear(old);
+               }
+       }
+
+       private void unwear(int index) {
+               unwear(wornItems.unwear(index));
+       }
+
+       public void unWear(String strStore) {
+               int index = Equipment.toIndex(strStore);
+
+               if (index != -1) {
+                       unwear(index);
+               } else if (strStore.equalsIgnoreCase("all")) {
+                       for (int i = 0; i < Equipment.WEARING_COUNT; i++) {
+                               unwear(i);
+                       }
+               } else {
+                       unwear(wornItems.unwearByName(strStore));
+               }
+               if (isPlayer()) {
+                       updateStats();
+                       updateEquipment();
+                       updateItems();
+               }
+       }
+
+       public void onWear(Item trigger) {
+               if (trigger.strOnWearScript != null) {
+                       try {
+                               Script scrStore = new Script("scripts/" + trigger.strOnWearScript, game, false);
+                               scrStore.varVariables.addVariable("trigger", this);
+                               scrStore.varVariables.addVariable("itemname", trigger.name);
+                               scrStore.varVariables.addVariable("mod", trigger.intMod);
+                               scrStore.runScript();
+                               scrStore.close();
+                       } catch (Exception e) {
+                       }
+               }
+       }
+
+       public void onUnwear(Item trigger) {
+               if (trigger.strOnUnWearScript != null) {
+                       try {
+                               Script scrStore = new Script("scripts/" + trigger.strOnUnWearScript, game, false);
+                               scrStore.varVariables.addVariable("trigger", this);
+                               scrStore.varVariables.addVariable("itemname", trigger.name);
+                               scrStore.varVariables.addVariable("mod", trigger.intMod);
+                               scrStore.runScript();
+                               scrStore.close();
+                       } catch (Exception e) {
+                       }
+               }
+       }
+
+       public boolean hasCondition(String strStore) {
+               for (Condition cndStore : conditions) {
+                       if (cndStore.name.equalsIgnoreCase(strStore)) {
+                               return true;
+                       }
+               }
+               return false;
+       }
+
+       public void addCondition(Condition cndStore) {
+               if (conditions.isEmpty()) {
+                       game.checkConditionList.add(this);
+               } else {
+                       for (int i = 0; i < conditions.size(); i++) {
+                               Condition cndStore2 = conditions.get(i);
+                               if (cndStore2.name.equalsIgnoreCase(cndStore.name)) {
+                                       conditions.remove(i);
+                                       i--;
+                                       cndStore2.onEnd(game, this);
+                               }
+                       }
+               }
+               conditions.add(cndStore);
+               cndStore.onStart(game, this);
+               updateStats();
+       }
+
+       public void removeCondition(String strName) {
+               Condition cndStore;
+               for (int i = 0; i < conditions.size(); i++) {
+                       cndStore = (Condition) conditions.get(i);
+                       if (strName.equalsIgnoreCase(cndStore.name)) {
+                               conditions.remove(i);
+                               if (conditions.isEmpty()) {
+                                       game.checkConditionList.remove(this);
+                               }
+                               cndStore.onEnd(game, this);
+                               updateStats();
+                               return;
+                       }
+               }
+               updateStats();
+       }
+
+       public DuskObject getLocalObject(String name) {
+               return game.findVisibleObject(this, name);
+       }
+
+       public void removeFromGroup() {
+               if (following != null && following.isPet()) {
+                       if (master != null) {
+                               try {
+                                       chatMessage("You are no longer following " + master.name + ".");
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       master.chatMessage(name + " is no longer following you.");
+                               } catch (Exception e) {
+                               }
+                               master.following = following.following;
+                       }
+                       if (following.following != null) {
+                               following.following.master = master;
+                       }
+                       if (!isPet()) {
+                               master = null;
+                       }
+                       following.following = null;
+               } else {
+                       if (master != null) {
+                               try {
+                                       chatMessage("You are no longer following " + master.name + ".");
+                               } catch (Exception e) {
+                               }
+                               try {
+                                       master.chatMessage(name + " is no longer following you.");
+                               } catch (Exception e) {
+                               }
+                               master.following = following;
+                       }
+                       if (following != null) {
+                               following.master = master;
+                       }
+                       if (!isPet()) {
+                               master = null;
+                       }
+                       following = null;
+               }
+       }
+
+       public void run() {
+               connectionThread = Thread.currentThread();
+               try {
+                       do {
+                               name = instream.readLine();
+                               if (name != null) {
+                                       name = name.trim();
+                               }
+                       } while (!getPlayer());
+                       if (!isWorking) {
+                               return;
+                       }
+               } catch (Exception e) {
+                       game.log.printError("LivingThing.run():start", e);
+                       closeNosavePlayer();
+                       return;
+               }
+               connectionThread.setName("LivingThing(" + name + ")");
+               sendThread.setName("LivingThing(" + name + ").send");
+               resizeMap();
+               changeLocBypass(x, y);
+               updateInfo();
+               updateStats();
+               updateItems();
+               updateEquipment();
+               updateActions();
+               if (game.blnMusic) {
+                       updateMusic();
+                       playMusic(0);
+               }
+               if (!(hasCondition("invis") && (privs > 2))) {
+                       game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " has entered the world");
+                       game.chatMessage(name + " has entered the world.", name);
+               } else {
+                       chatMessage("You have entered the world hidden from players.");
+                       game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " has entered the world hidden from players");
+               }
+               String strInput,
+                               strStore;
+               isSaveable = true;
+               isReady = true;
+               while (true) {
+                       if (isStopped) {
+                               return;
+                       }
+                       try {
+                               if (!isHalted) {
+                                       strInput = instream.readLine();
+                                       if (strInput != null) {
+                                               strInput = strInput.trim();
+                                       }
+                                       strStore = Commands.parseCommand(this, game, strInput);
+                                       if (strStore != null) {
+                                               chatMessage(strStore);
+                                       }
+                               }
+                       } catch (Exception e) {
+                               game.log.printError("LivingThing.run():" + name + " disconnected", e);
+                               close();
+                               return;
+                       }
+               }
+       }
+
+       boolean getPlayer() {
+               if (!game.isGoodName(name)) {
+                       chatMessage("Not a valid name. This may because you left it blank, used invalid symbols, or made it too long. Please try again.");
+                       return false;
+               }
+               String strStore;
+               int i;
+               LivingThing thnStore;
+               try {
+                       File filStore = new File("users/" + name.toLowerCase());
+                       if (!filStore.exists() || filStore.length() < 100) {
+                               File filBackup = new File("users/" + name.toLowerCase() + ".backup");
+                               if (filBackup.exists()) {
+                                       filBackup.renameTo(filStore);
+                               }
+                       }
+
+                       String strIP = socket.getInetAddress().toString();
+                       int ip = strIP.indexOf("/");
+                       strIP = strIP.substring(ip + 1, strIP.length());
+
+                       if (filStore.exists()) {
+                               try (RandomAccessFile rafFile = new RandomAccessFile("users/" + name.toLowerCase(), "r")) {
+                                       chatMessage("enter your password:");
+                                       password = instream.readLine();
+                                       if (!password.equals(rafFile.readLine())) {
+                                               rafFile.close();
+                                               game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " entered the wrong password");
+                                               Variable failCount = game.varIP.getVariable(strIP);
+                                               if (failCount != null) {
+                                                       int fc = failCount.intValue();
+                                                       if (fc >= 4) {
+                                                               game.banAddress(strIP);
+                                                               chatMessage("Too many login failures, try again in an hour.");
+                                                               send("Goodbye.\n" + (char) 0);
+                                                               Thread.sleep(1000);
+                                                               closeNosavePlayer();
+                                                               rafFile.close();
+                                                               return true;
+                                                       } else {
+                                                               game.varIP.addVariable(strIP, fc + 1);
+                                                       }
+                                               } else {
+                                                       game.varIP.addVariable(strIP, (double) 1);
+                                               }
+                                               Thread.sleep(3000);
+                                               chatMessage("Incorrect Password.");
+                                               chatMessage("Enter your login name: ");
+                                               return false;
+                                       }
+                               } catch (Exception e) {
+                                       game.log.printError("getPlayer():" + socket.getInetAddress().toString() + ":" + name, e);
+                                       closeNosavePlayer();
+                                       return true;
+                               }
+                       } else {
+                               File fileStore = new File("pets/" + name.toLowerCase());
+                               if (fileStore.exists()) {
+                                       chatMessage(name + " is already in use.  Please choose another.");
+                                       return false;
+                               }
+                               chatMessage(name + ", Is that correct? (yes/no)");
+                               if (!instream.readLine().equalsIgnoreCase("yes")) {
+                                       chatMessage("Then what IS your name?");
+                                       return false;
+                               }
+                               chatMessage("Enter a new password:");
+                               password = instream.readLine();
+                               chatMessage("Confirm that password:");
+                               while (!password.equals(instream.readLine())) {
+                                       chatMessage("Passwords did not match, enter a new password:");
+                                       password = instream.readLine();
+                                       chatMessage("Confirm that password:");
+                               }
+                       }
+                       game.varIP.removeVariable(strIP);
+                       try {
+                               wornItems = new Equipment();
+                               itemList = new ItemList();
+                               conditions.clear();
+                               nearEntities.clear();
+                               flags.clear();
+                               ignoreList.clear();
+                               chatMessage("Login Accepted.");
+                               proceed();
+                               chatMessage("This game is running DuskServer v" + game.version + ". http://dusk.wesowin.org/");
+                               chatMessage("Started at " + game.datStart.toString() + ".");
+                               for (LivingThing lt : game.playersByName.values()) {
+                                       if (name.equalsIgnoreCase(lt.name)) {
+                                               game.log.printMessage(Log.INFO, socket.getInetAddress().toString() + ":" + name + " tried to log in twice");
+                                               chatMessage("That user is already logged in. They are being logged out.");
+                                               lt.chatMessage("There has been another logon under this name, you are being logged out.");
+                                               lt.close();
+                                               break;
+                                       }
+                                       // Second IP Filter check to catch delayed sign-ons
+                                       if (game.blnIPF) {
+                                               String IP = lt.socket.getInetAddress().toString();
+                                               if (IP.equalsIgnoreCase(socket.getInetAddress().toString())) {
+                                                       chatMessage("There's already a player connected from your IP address.");
+                                                       Thread.sleep(1000);
+                                                       closeNosavePlayer();
+                                                       return false;
+                                               }
+                                       }
+                               }
+                               game.playersByName.put(this.name.toLowerCase(), this);
+                               game.onStart(this);
+                               try (RandomAccessFile rafFile = new RandomAccessFile("users/default", "r")) {
+                                       strStore = rafFile.readLine();
+                                       while (!(strStore == null || strStore.equals("."))) {
+                                               parseUserFile(rafFile, strStore);
+                                               strStore = rafFile.readLine();
+                                       }
+                               }
+                       } catch (Exception e) {
+                               game.log.printError("getPlayer():While loading default user file for " + name, e);
+                       }
+                       strStore = name.toLowerCase();
+                       File filPlayer = new File("users/" + strStore);
+                       File filBackup = new File("users/" + strStore + ".backup");
+                       File filCheck;
+                       int i2 = 0;
+                       if (filBackup.exists()) {
+                               if (filPlayer.length() > filBackup.length()) {
+                                       filCheck = new File("backup/" + strStore + ".possiblyDamaged");
+                                       while (filCheck.exists()) {
+                                               i2++;
+                                               filCheck = new File("backup/" + strStore + ".possiblyDamaged." + i2);
+                                       }
+                                       filBackup.renameTo(filCheck);
+                               } else if (filPlayer.length() < filBackup.length()) {
+                                       filCheck = new File("backup/" + strStore + ".possiblyDamaged");
+                                       while (filCheck.exists()) {
+                                               i2++;
+                                               filCheck = new File("backup/" + strStore + ".possiblyDamaged." + i2);
+                                       }
+                                       filPlayer.renameTo(filCheck);
+                                       filBackup.renameTo(new File("users/" + strStore));
+                               }
+                       }
+                       /*
+                        ** Load the user
+                        */
+                       file = new File("users/", strStore);
+                       backup = new File("users/", strStore + ".backup");
+                       try (RandomAccessFile rafFile = new RandomAccessFile(file, "rw")) {
+                               strStore = rafFile.readLine();
+                               while (!(strStore == null || strStore.equals("."))) {
+                                       parseUserFile(rafFile, strStore);
+                                       strStore = rafFile.readLine();
+                               }
+                       }
+                       /*
+                        ** Try to load a pet, if they don't already have one
+                        */
+                       if (following == null) {
+                               following = new LivingThing("default", null, this, game);
+                               if (following.name.equalsIgnoreCase("default")) {
+                                       following.closeNosavePlayer();
+                                       following = null;
+                               }
+                       }
+               } catch (Exception e) {
+                       game.log.printError("getPlayer():While loading file for " + name, e);
+                       closeNosavePlayer();
+                       return true;
+               }
+               loadRace();
+               isLoaded = true;
+               if (following != null) {
+                       following.isLoaded = true;
+                       following.changeLocBypass(x, y);
+               }
+               return true;
+       }
+
+       String askRace(String strRaceDir, String prompt) throws IOException {
+               File filRaces = new File(strRaceDir);
+               String strList[] = filRaces.list();
+               StringBuilder sb = new StringBuilder(prompt);
+               sb.append("\n");
+               for (String s : strList) {
+                       sb.append(s).append("\n");
+               }
+               sb.append(".\n");
+               String s = sb.toString();
+
+               // ??
+               if (isPlayer()) {
+                       send(MessageType.ChooseRace, s);
+               }
+               if (charmer != null) {
+                       charmer.send(MessageType.ChooseRace, s);
+               }
+               if (isPet()) {
+                       return master.instream.readLine().toLowerCase();
+               } else {
+                       return instream.readLine().toLowerCase();
+               }
+       }
+
+       public void loadRace() {
+               String s;
+               String dir;
+               if (isPet()) {
+                       dir = "defPets";
+               } else {
+                       dir = "defRaces";
+               }
+               try {
+                       if (race == null || !(new File(dir + "/" + race).exists())) {
+                               s = askRace(dir, "Choose one of the following races:");
+                               // FIXME: check this isn't broken
+                               File filCheck = new File(dir + "/" + s);
+                               while (s.equals("") || !filCheck.exists()) {
+                                       s = askRace(dir, "That is not a valid race, please choose again.");
+                                       filCheck = new File(dir + "/" + s);
+                               }
+                               race = s;
+                       }
+                       loadRaceFile(new File(dir + "/" + race), true);
+               } catch (Exception e) {
+                       game.log.printError("loadRace():Loading " + name + "'s race file \"" + dir + "/" + race + "\"", e);
+               }
+       }
+
+       public void unloadRace() {
+               String dir;
+               if (isPet()) {
+                       dir = "defPets";
+               } else {
+                       dir = "defRaces";
+               }
+               try {
+                       if (race == null || !(new File(dir + "/" + race).exists())) {
+                               race = null;
+                               return;
+                       }
+                       loadRaceFile(new File(dir + "/" + race), false);
+               } catch (Exception e) {
+                       game.log.printError("unloadRace():Un-loading " + name + "'s race file \"" + dir + "/" + race + "\"", e);
+               }
+               race = null;
+       }
+
+       public void updateAppletImages() {
+               String strResult = "" + (char) 1;
+               strResult += game.strRCAddress + "\n";
+               try {
+                       send(strResult);
+               } catch (Exception e) {
+                       game.log.printError("updateAppletImages()", e);
+               }
+       }
+
+       public void updateApplicationImages() {
+               String strResult = "" + (char) 1;
+               strResult += game.strRCName + "\n";
+               try {
+                       send(strResult);
+               } catch (Exception e) {
+                       game.log.printError("updateApplicationImages()", e);
+               }
+       }
+
+       public void updateMusic() {
+               /*try
+                {
+                String strResult="";
+                String strStore,
+                strStore2;
+                int count=0;
+                RandomAccessFile rafMusic;
+                       
+                rafMusic = new RandomAccessFile("music0","r");
+                strStore = "";
+                try
+                {
+                strStore2 = rafMusic.readLine();
+                while (!(strStore2 == null || strStore2.equals("")))
+                {
+                strStore += strStore2+"\n";
+                strStore2 = rafMusic.readLine();
+                count++;
+                }
+                }catch (Exception e)
+                {
+                }
+                strResult += ""+count+"\n"+strStore;
+                rafMusic.close();
+                rafMusic = new RandomAccessFile("music1","r");
+                strStore = "";
+                count=0;
+                try
+                {
+                strStore2 = rafMusic.readLine();
+                while (!(strStore2 == null || strStore2.equals("")))
+                {
+                strStore += strStore2+"\n";
+                strStore2 = rafMusic.readLine();
+                count++;
+                }
+                }catch (Exception e)
+                {
+                }
+                rafMusic.close();
+                strResult += ""+count+"\n"+strStore;
+                send((char)11+""+2+"\n"+strResult);
+                }catch(Exception e)
+                {
+                engGame.log.printError("updateMusic()", e);
+                }*/
+       }
+
+       public void playMusic(int type) {
+               /*try
+                {
+                send(""+((char)12)+""+type+"\n");
+                }catch(Exception e)
+                {
+                engGame.log.printError("playMusic()", e);
+                }*/
+       }
+
+       public void playSFX(int intSFX) {
+               if (audioon) {
+                       try {
+                               send((char) 15 + "" + intSFX + "\n");
+                       } catch (Exception e) {
+                               game.log.printError("playSFX()", e);
+                       }
+               }
+       }
+
+       public void updateActions() {
+               try {
+                       if (isPlayer()) {
+                               String strResult = "" + (char) 10;
+                               if (battle != null) {
+                                       strResult += "flee\n";
+                               } else {
+                                       if (isSleeping) {
+                                               strResult += "wake\n";
+                                       } else {
+                                               strResult += "sleep\n";
+                                       }
+                               }
+                               strResult += ".\n";
+                               send(strResult);
+                       }
+               } catch (Exception e) {
+                       game.log.printError("updateActions()", e);
+               }
+       }
+
+       // FIXME: I think this should be encapsulated in a more desriptive message
+       public void updateEquipment() {
+               try {
+                       send(MessageType.UpdateEquipment, wornItems.toEntity());
+               } catch (Exception e) {
+                       game.log.printError("updateEquipment():" + name + " disconnected", e);
+                       isStopped = true;
+                       return;
+               }
+       }
+
+       public void send(MessageType type, String data) {
+               if (isPlayer() && isWorking && !isClosing) {
+                       // FIXME: put code in senddata
+                       messageQueue.offer(ServerMessage.stringMessage(type, data));
+               }
+       }
+
+       public void send(ServerMessage msg) {
+               if (isPlayer() && isWorking && !isClosing) {
+                       messageQueue.offer(msg);
+               }
+       }
+
+       public void send(String data) {
+               if (isPlayer() && isWorking && !isClosing) {
+                       messageQueue.offer(ServerMessage.stringMessage(data));
+               }
+       }
+
+       /*      public void send(byte data)
+        {
+        if (isPlayer() && blnWorking && !blnIsClosing)
+        {
+        SendData sd = new SendData(data);
+        qMessage.push(sd);
+        }
+        }
+       
+        public void send(long data)
+        {
+        if (isPlayer() && blnWorking && !blnIsClosing)
+        {
+        SendData sd = new SendData(data);
+        qMessage.push(sd);
+        }
+        }*/
+       public void updateInfo() {
+               try {
+                       String strResult;
+                       strResult = hp + "\n";
+                       strResult += (maxhp + hpbon) + "\n";
+                       strResult += mp + "\n";
+                       strResult += (maxmp + mpbon) + "\n";
+                       send(MessageType.UpdateStats, strResult);
+               } catch (Exception e) {
+                       game.log.printError("updateInfo():" + name + " disconnected", e);
+                       isStopped = true;
+               }
+       }
+
+       public void updateRange() {
+               try {
+                       String strResult = "" + (char) 28;
+                       strResult += getRangeWithBonus() + "\n";
+                       send(strResult);
+               } catch (Exception e) {
+                       game.log.printError("updateRange():" + name + " disconnected", e);
+               }
+       }
+
+       public void updateItems() {
+               try {
+                       StringBuilder sb = new StringBuilder();
+
+                       for (LinkedList<Item> qStore : itemList.values()) {
+                               if (qStore.size() > 0) {
+                                       Item itmStore = (Item) qStore.element();
+                                       if (itmStore.isArmor()) {
+                                               sb.append((2 + itmStore.intKind) + "\n");
+                                       } else if (itmStore.isWeapon()) {
+                                               sb.append("1\n");
+                                       } else {
+                                               sb.append("0\n");
+                                       }
+                                       sb.append(itmStore.name + "\n");
+                               }
+                       }
+                       sb.append(".\n");
+                       send(MessageType.UpdateItems, sb.toString());
+                       if (game.overMerchant(x, y) != null) {
+                               updateSell();
+                       }
+                       if (game.overPlayerMerchant(x, y) != null) {
+                               updateSell();
+                       }
+               } catch (Exception e) {
+                       game.log.printError("updateItems():" + name + " disconnected", e);
+                       isStopped = true;
+               }
+               isSaveNeeded = true;
+       }
+
+       public void updateStats() {
+               SpellGroup grpStore;
+               int i,
+                               i2;
+
+               // FIXME: wtf, duplicated shit code again
+               // FIXME: convert to stringbuilder
+               try {
+                       String strResult = "";
+                       strResult += cash + " gp\n";
+                       strResult += exp + " exp\n";
+                       if (strebon == 0) {
+                               strResult += "str: " + stre + "\n";
+                       } else {
+                               strResult += "str: " + stre + " + " + strebon + "\n";
+                       }
+                       if (intebon == 0) {
+                               strResult += "int: " + inte + "\n";
+                       } else {
+                               strResult += "int: " + inte + " + " + intebon + "\n";
+                       }
+                       if (dextbon == 0) {
+                               strResult += "dex: " + dext + "\n";
+                       } else {
+                               strResult += "dex: " + dext + " + " + dextbon + "\n";
+                       }
+                       if (consbon == 0) {
+                               strResult += "con: " + cons + "\n";
+                       } else {
+                               strResult += "con: " + cons + " + " + consbon + "\n";
+                       }
+                       if (wisdbon == 0) {
+                               strResult += "wis: " + wisd + "\n";
+                       } else {
+                               strResult += "wis: " + wisd + " + " + wisdbon + "\n";
+                       }
+                       if (dammodbon == 0) {
+                               strResult += "DamMod: " + getDamMod() + "\n";
+                       } else {
+                               strResult += "DamMod: " + getDamMod() + " + " + dammodbon + "\n";
+                       }
+                       if (acbon == 0) {
+                               strResult += "AC: " + getArmorMod() + "\n\n";
+                       } else {
+                               strResult += "AC: " + getArmorMod() + " + " + acbon + "\n";
+                       }
+                       strResult += "-Affected by-\n";
+                       for (Condition cond : conditions) {
+                               if (cond.display) {
+                                       strResult += cond.name + "\n";
+                               }
+                       }
+                       strResult += "-Skills-\n";
+                       for (Ability skill : skillMap.values()) {
+                               strResult += skill.name + ": " + skill.getAbility() + "\n";
+                       }
+                       strResult += "-Spells-\n";
+                       for (Ability spell : spellMap.values()) {
+                               grpStore = game.getSpellGroup(spell.name);
+                               if (grpStore != null) {
+                                       strResult += spell.name + ": " + spell.getAbility() + "\n";
+                                       strResult += grpStore.spellList(spell.getAbility());
+                               }
+                       }
+                       if (master != null) {
+                               strResult += "\nFollowing: " + master.name + "\n";
+                       }
+                       if (following != null) {
+                               strResult += "\nFollowed By: " + following.name + "\n";
+                               if (following.isPet()) {
+                                       strResult += following.hp + "/" + following.maxhp + " hp\n";
+                                       strResult += following.mp + "/" + following.maxmp + " mp\n";
+                                       strResult += following.cash + " gp\n";
+                                       strResult += following.exp + " exp\n";
+                                       if (following.strebon == 0) {
+                                               strResult += "str: " + following.stre + "\n";
+                                       } else {
+                                               strResult += "str: " + following.stre + " + " + following.strebon + "\n";
+                                       }
+                                       if (following.intebon == 0) {
+                                               strResult += "int: " + following.inte + "\n";
+                                       } else {
+                                               strResult += "int: " + following.inte + " + " + following.intebon + "\n";
+                                       }
+                                       if (following.dextbon == 0) {
+                                               strResult += "dex: " + following.dext + "\n";
+                                       } else {
+                                               strResult += "dex: " + following.dext + " + " + following.dextbon + "\n";
+                                       }
+                                       if (following.consbon == 0) {
+                                               strResult += "con: " + following.cons + "\n";
+                                       } else {
+                                               strResult += "con: " + following.cons + " + " + following.consbon + "\n";
+                                       }
+                                       if (following.wisdbon == 0) {
+                                               strResult += "wis: " + following.wisd + "\n";
+                                       } else {
+                                               strResult += "wis: " + following.wisd + " + " + following.wisdbon + "\n";
+                                       }
+                                       if (following.dammodbon == 0) {
+                                               strResult += "DamMod: " + following.getDamMod() + "\n";
+                                       } else {
+                                               strResult += "DamMod: " + following.getDamMod() + " + " + following.dammodbon + "\n";
+                                       }
+                                       if (following.acbon == 0) {
+                                               strResult += "AC: " + following.getArmorMod() + "\n\n";
+                                       } else {
+                                               strResult += "AC: " + following.getArmorMod() + " + " + following.acbon + "\n";
+                                       }
+                                       strResult += "-Affected by-\n";
+                                       for (Condition cndStore : following.conditions) {
+                                               if (cndStore.display) {
+                                                       strResult += cndStore.name + "\n";
+                                               }
+                                       }
+                                       strResult += "-Skills-\n";
+                                       for (Ability skill : following.skillMap.values()) {
+                                               strResult += skill.name + ": " + skill.getAbility() + "\n";
+                                       }
+                                       strResult += "-Spells-\n";
+                                       for (Ability spell : following.skillMap.values()) {
+                                               grpStore = game.getSpellGroup(spell.name);
+                                               if (grpStore != null) {
+                                                       strResult += spell.name + ": " + spell.getAbility() + "\n";
+                                                       strResult += grpStore.spellList(spell.getAbility());
+                                               }
+                                       }
+                               }
+                       }
+                       strResult += ".\n";
+                       send(MessageType.UpdateInfo, strResult);
+               } catch (Exception e) {
+                       game.log.printError("updateStats():" + name + " disconnected", e);
+                       isStopped = true;
+               }
+               //updateRange();
+               isSaveNeeded = true;
+       }
+
+       public void halt() {
+               isHalted = true;
+               try {
+                       send(MessageType.Halt, "");
+               } catch (Exception e) {
+                       isHalted = false;
+                       game.log.printError("halt()", e);
+               }
+       }
+
+       public void proceed() {
+               isHalted = false;
+               try {
+                       send(MessageType.Proceed, ID + "\n");
+               } catch (Exception e) {
+                       game.log.printError("proceed()", e);
+               }
+       }
+
+       public void stillThere() {
+               try {
+                       send("" + (char) 13);
+               } catch (Exception e) {
+                       game.log.printError("stillThere()", e);
+               }
+       }
+
+       public void resizeMap() {
+               int i, i2;
+               String strResult = (char) 19 + "";
+               strResult += game.mapsize + "\n";
+               send(strResult);
+       }
+
+       public void updateSell() {
+               StringBuilder sb = new StringBuilder();
+
+               for (LinkedList<Item> list : itemList.values()) {
+                       for (Item item : list) {
+                               sb.append(item.intCost / 2).append("gp)").append(item.name).append("\n");
+                       }
+               }
+               sb.append(".\n");
+               send(MessageType.UpdateSell, sb.toString());
+       }
+
+       void offMerchant() {
+               send(MessageType.ExitMerchant, "");
+       }
+
+       private class SendThread extends Thread {
+
+               public SendThread() {
+               }
+
+               public void run() {
+                       ServerMessage msg;
+                       while (!isStopped) {
+                               try {
+                                       msg = messageQueue.take();
+                                       try {
+                                               msg.send(outstream);
+                                               outstream.flush();
+                                       } catch (IOException e) {
+                                               game.log.printError("SendThread.run():" + msg + " to " + name, e);
+                                               isWorking = false;
+                                               isStopped = true;
+                                               close();
+                                       }
+                               } catch (InterruptedException ex) {
+                                       Logger.getLogger(SendThread.class.getName()).log(Level.SEVERE, null, ex);
+                               }
+                       }
+               }
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Merchant.java b/DuskServer/src/duskz/server/entity/Merchant.java
new file mode 100644 (file)
index 0000000..ca9764c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java.
+ */
+package duskz.server.entity;
+
+import duskz.server.DuskEngine;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Merchant represents a non-mobile entity where players can buy/sell items and
+ * pets or train.
+ *
+ * @author Tom Weingarten
+ */
+public class Merchant extends DuskObject {
+
+       DuskEngine engGame;
+       public final List<String> items = new ArrayList<>();
+
+       public Merchant(DuskEngine inGame) {
+               super(inGame.getID(), "Merchant");
+               engGame = inGame;
+       }
+
+       @Override
+       public int getImage() {
+               return engGame.merchantimage;
+       }
+
+       @Override
+       public byte getType() {
+               return MERCHANT;
+       }
+
+       @Override
+       public int getEntityType() {
+               return 2;
+       }
+
+       public boolean contains(String item) {
+               return items.contains(item);
+       }
+
+       public void remove(String item) {
+               items.remove(item);
+       }
+
+       public void pet(LivingThing thnMaster) {
+               try {
+                       if (thnMaster.following != null && thnMaster.following.isPet()) {
+                               thnMaster.chatMessage("You are only allowed 1 pet.");
+                               return;
+                       }
+                       if (thnMaster.cash >= engGame.petcost) {
+                               thnMaster.cash -= engGame.petcost;
+                       } else {
+                               thnMaster.chatMessage("You can't afford a pet.");
+                               return;
+                       }
+                       if (thnMaster.isPet()) {
+                               thnMaster.chatMessage("You ARE a pet!");
+                               return;
+                       }
+                       thnMaster.halt();
+                       thnMaster.chatMessage("Enter a name for your pet:");
+                       String strName = thnMaster.instream.readLine().trim();
+                       File filCheck = new File("pets/" + strName.toLowerCase());
+                       File filCheck2 = new File("users/" + strName.toLowerCase());
+                       while (filCheck.exists() || filCheck2.exists()
+                                       || !engGame.isGoodName(strName)) {
+                               thnMaster.chatMessage("That name is already taken or has invalid characters, please enter another:");
+                               strName = thnMaster.instream.readLine().trim();
+                               filCheck = new File("pets/" + strName.toLowerCase());
+                               filCheck2 = new File("users/" + strName.toLowerCase());
+                       }
+                       thnMaster.chatMessage("Choose a type of pet:");
+                       File filPetTypes = new File("defPets");
+                       String strList[] = filPetTypes.list();
+                       for (int i = 0; i < strList.length; i++) {
+                               thnMaster.chatMessage(strList[i]);
+                       }
+                       String strStore = thnMaster.instream.readLine().trim();
+                       filCheck = new File("defPets/" + strStore);
+                       while (strStore.equals("") || !filCheck.exists()) {
+                               thnMaster.chatMessage("That is not a valid pet type:");
+                               strStore = thnMaster.instream.readLine().trim();
+                               filCheck = new File("defPets/" + strStore);
+                       }
+                       thnMaster.following = new LivingThing(strName, strStore, thnMaster, engGame);
+               } catch (Exception e) {
+                       engGame.log.printError("Merchant.pet()", e);
+               } finally {
+                       thnMaster.proceed();
+               }
+       }
+
+       public void train(String how, int quantity, LivingThing lt) {
+               quantity = Math.min(quantity, 100);
+
+               if (lt.exp < engGame.traincost * quantity) {
+                       lt.chatMessage("Sorry, you don't have enough experience points.");
+                       return;
+               }
+
+               switch (how.toLowerCase()) {
+                       case "hp":
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.maxhp += 10 * quantity;
+                               lt.hp += 10 * quantity;
+                               lt.updateInfo();
+                               break;
+                       case "mp":
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.maxmp += 10 * quantity;
+                               lt.mp += 10 * quantity;
+                               lt.updateInfo();
+                               break;
+                       case "strength":
+                               if (lt.stre + quantity > lt.stre_limit) {
+                                       quantity = lt.stre_limit - lt.stre;
+                               }
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.stre += quantity;
+                               break;
+                       case "intelligence":
+                               if (lt.inte + quantity > lt.inte_limit) {
+                                       quantity = lt.inte_limit - lt.inte;
+                               }
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.inte += quantity;
+                               break;
+                       case "wisdom":
+                               if (lt.wisd + quantity > lt.wisd_limit) {
+                                       quantity = lt.wisd_limit - lt.wisd;
+                               }
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.wisd += quantity;
+                               break;
+                       case "constitution":
+                               if (lt.cons + quantity > lt.cons_limit) {
+                                       quantity = lt.cons_limit - lt.cons;
+                               }
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.cons += quantity;
+                               break;
+                       case "dexterity":
+                               if (lt.dext + quantity > lt.dext_limit) {
+                                       quantity = lt.dext_limit - lt.dext;
+                               }
+                               lt.exp -= engGame.traincost * quantity;
+                               lt.dext += quantity;
+                               break;
+                       default:
+                               int skillLeft = 100 - lt.getSkill(how);
+                               if (quantity > skillLeft) {
+                                       quantity = skillLeft;
+                               }
+                               if (lt.addToSkill(how, (byte) quantity)) {
+                                       lt.exp -= quantity * engGame.traincost;
+                               } else {
+                                       return;
+                               }
+               }
+               lt.updateStats();
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Mob.java b/DuskServer/src/duskz/server/entity/Mob.java
new file mode 100644 (file)
index 0000000..b053714
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, script wrapper,
+ * loader function.
+ */
+package duskz.server.entity;
+
+import duskz.server.Condition;
+import duskz.server.DuskEngine;
+import duskz.server.Faction;
+import duskz.server.GiveItem;
+import duskz.server.ItemList;
+import duskz.server.Log;
+import duskz.server.Script;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Mob(mobile) is the class of non-player moving entities.
+ *
+ * @author Tom Weingarten
+ */
+public class Mob extends LivingThing {
+
+       final public List<GiveItem> vctGiveItems = new ArrayList<>();
+       //Mob level
+       public int level = -1;
+       //AI
+       public double dblBravery = 0, //0 to 1, -1 makes mob always flee
+                       dblGroupRelation = 0;  //-1 to 1
+       public String strOnBattle = null;
+       //Faction
+       public Faction fctFaction;
+       public boolean blnOneUse = false;
+       public boolean blnCanSeePlayer = false;
+
+       //new Mob
+       public Mob(String strType, int locx, int locy, DuskEngine inEngine)
+                       throws Exception {
+               super(inEngine.getID(), strType);
+               noChannel = -1;
+               game = inEngine;
+               Type = 1;
+               race = strType;
+               x = locx;
+               y = locy;
+               originalX = x;
+               originalY = y;
+               wornItems = new Equipment();
+               itemList = new ItemList();
+               battle = null;
+               loadMobFile(new File("defMobs/" + strType));
+               hp = maxhp;
+               mp = maxmp;
+               isSleeping = false;
+               isLoaded = true;
+       }
+
+       //new Mob w/ levels (provided for pre-2.3 compatibility)
+       public Mob(String strType, int level, int locx, int locy, DuskEngine inEngine)
+                       throws Exception {
+               super(inEngine.getID(), strType);
+               noChannel = -1;
+               game = inEngine;
+               Type = 1;
+               race = strType;
+               x = locx;
+               y = locy;
+               originalX = x;
+               originalY = y;
+               wornItems = new Equipment();
+               itemList = new ItemList();
+               battle = null;
+               this.level = level;
+               loadMobFile(new File("defMobs/" + strType));
+               maxhp = maxhp * level;
+               maxmp = maxmp * level;
+               stre = stre * level;
+               inte = inte * level;
+               wisd = wisd * level;
+               dext = dext * level;
+               cons = cons * level;
+               hp = maxhp * level;
+               mp = maxmp * level;
+               isSleeping = false;
+               isLoaded = true;
+       }
+
+       @Override
+       public void leaveBattle() {
+               super.leaveBattle();
+               if (blnOneUse) {
+                       game.removeDuskObject(this);
+               } else {
+                       game.mobKilled(this);
+                       // FIXME: need a game.mobKilled() function
+                       // FIXME: this magic number is used in TickThread and DuskEngine
+                       x = -6;
+                       y = -6;
+                       hp = game.mobrespawnspeed;//seconds till respawn
+               }
+       }
+
+       public void loadMobFile(File path) throws FileNotFoundException, IOException {
+               String line;
+               try (RandomAccessFile file = new RandomAccessFile(path, "r")) {
+                       while (!((line = file.readLine()) == null || line.equals("."))) {
+                               try {
+                                       parseMobFile(file, line);
+                               } catch (NumberFormatException x) {
+                                       throw new IOException("Problem parsing mob " + path + " on field " + line, x);
+                               }
+                       }
+                       if (fctFaction == null) {
+                               game.log.printMessage(Log.DEBUG, "no faction found for mob \"" + name + "\"");
+                       }
+               }
+       }
+
+       private void parseMobFile(RandomAccessFile in, String strStore) throws IOException, NumberFormatException {
+               switch (strStore.toLowerCase()) {
+                       case "skill":
+                               strStore = in.readLine();
+                               int value = Byte.parseByte(in.readLine());
+                               addToSkill(strStore, value);
+                               game.log.printMessage(Log.DEBUG, strStore + "=" + value);
+                               break;
+                       case "condition":
+                               Condition cndStore = game.getCondition(in.readLine());
+                               cndStore.ticksPast = Integer.parseInt(in.readLine());
+                               cndStore.duration = Integer.parseInt(in.readLine());
+                               addCondition(cndStore);
+                               game.log.printMessage(Log.DEBUG, "condition \"" + cndStore.name + "\"");
+                               break;
+                       case "giveitem":
+                               String strItem = in.readLine();
+                               double dblChance = Double.valueOf(in.readLine()).doubleValue();
+                               vctGiveItems.add(new GiveItem(strItem, dblChance));
+                               game.log.printMessage(Log.DEBUG, name + " gives a \"" + strItem + "\" " + (100 * dblChance) + "% of the time.");
+                               break;
+                       case "item":
+                               Item itmStore = game.getItem(in.readLine());
+                               if (itmStore != null) {
+                                       itmStore.lngDurability = Long.parseLong(in.readLine());
+                                       itmStore.intUses = Integer.parseInt(in.readLine());
+                                       itemList.addElement(itmStore);
+                               }
+                               break;
+                       case "clan":
+                               clan = in.readLine();
+                               break;
+                       case "race":
+                               race = in.readLine();
+                               break;
+                       case "title":
+                               title = in.readLine();
+                               break;
+                       case "description":
+                               description = in.readLine();
+                               break;
+                       case "x":
+                               x = Integer.parseInt(in.readLine());
+                               break;
+                       case "y":
+                               y = Integer.parseInt(in.readLine());
+                               break;
+                       case "maxhp":
+                               maxhp = Integer.parseInt(in.readLine());
+                               break;
+                       case "maxmp":
+                               maxmp = Integer.parseInt(in.readLine());
+                               break;
+                       case "stre":
+                               stre = Integer.parseInt(in.readLine());
+                               break;
+                       case "inte":
+                               inte = Integer.parseInt(in.readLine());
+                               break;
+                       case "dext":
+                               dext = Integer.parseInt(in.readLine());
+                               break;
+                       case "cons":
+                               cons = Integer.parseInt(in.readLine());
+                               break;
+                       case "wisd":
+                               wisd = Integer.parseInt(in.readLine());
+                               break;
+                       case "image":
+                               imageid = Integer.parseInt(in.readLine());
+                               break;
+                       case "bravery":
+                               dblBravery = Double.valueOf(in.readLine()).doubleValue();
+                               break;
+                       case "grouprelation":
+                               dblGroupRelation = Double.valueOf(in.readLine()).doubleValue();
+                               break;
+                       case "wield":
+                               parseWear(in, Equipment.WIELD);
+                               break;
+                       case "arms":
+                               parseWear(in, Equipment.ARMS);
+                               break;
+                       case "legs":
+                               parseWear(in, Equipment.LEGS);
+                               break;
+                       case "torso":
+                               parseWear(in, Equipment.TORSO);
+                               break;
+                       case "waist":
+                               parseWear(in, Equipment.WAIST);
+                               break;
+                       case "neck":
+                               parseWear(in, Equipment.NECK);
+                               break;
+                       case "skull":
+                               parseWear(in, Equipment.SKULL);
+                               break;
+                       case "eyes":
+                               parseWear(in, Equipment.EYES);
+                               break;
+                       case "hands":
+                               parseWear(in, Equipment.HANDS);
+                               break;
+                       case "faction":
+                               String strFaction = in.readLine();
+                               fctFaction = game.getFaction(strFaction);
+                               if (fctFaction != null) {
+                                       game.log.printMessage(Log.DEBUG, "faction=\"" + fctFaction.strName + "\"");
+                               } else {
+                                       game.log.printMessage(Log.DEBUG, "no faction found for \"" + strFaction + "\"");
+                               }
+                               break;
+                       case "onBattle":
+                               strOnBattle = in.readLine();
+                               break;
+                       case "nofollow":
+                               noFollow = true;
+                               break;
+               }
+               //      engGame.log.printError("parseMobFile():Parsing \"" + strStore + "\" from " + name + "'s file", e);
+       }
+
+       public void onBattle(DuskEngine engGame) {
+               Script.exec("scripts/" + strOnBattle, engGame, this);
+       }
+}
\ No newline at end of file
diff --git a/DuskServer/src/duskz/server/entity/PlayerMerchant.java b/DuskServer/src/duskz/server/entity/PlayerMerchant.java
new file mode 100644 (file)
index 0000000..3006db6
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server.entity;
+
+import duskz.server.DuskEngine;
+import duskz.server.ItemList;
+
+/**
+ * Merchant represents a non-mobile entity where This merchant holds/sells items
+ * for the player that owns it The owner can give and take items and gp from it.
+ * The merchant will only be able to sell items it has been given. And only the
+ * number it has been given.
+ *
+ * @author Wildern
+ */
+public class PlayerMerchant extends DuskObject {
+
+       DuskEngine engGame;
+       public ItemList vctItems;
+       // FIXME: not public!!
+       public long cash;
+       public String strOwner;
+
+       public PlayerMerchant(DuskEngine inGame) {
+               super(inGame.getID(), "Merchant");
+               engGame = inGame;
+       }
+
+       @Override
+       public int getImage() {
+               return engGame.merchantimage;
+       }
+
+       @Override
+       public byte getType() {
+               return PLAYER_MARCHANT;
+       }
+
+       @Override
+       public int getEntityType() {
+               return 2;
+       }
+
+       public long contains(String strStore) {
+               if (vctItems.contains(strStore)) {
+                       return vctItems.get(strStore).size();
+               }
+               return 0;
+       }
+
+       public void add(Item itmStore) {
+               vctItems.addElement(itmStore);
+       }
+
+       public Item remove(String strStore) {
+               return vctItems.removeElement(strStore);
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Prop.java b/DuskServer/src/duskz/server/entity/Prop.java
new file mode 100644 (file)
index 0000000..da5cdb0
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server.entity;
+
+/**
+ * A Prop is an entity that cannot move or be used.
+ *
+ * @author Tom Weingarten
+ */
+public class Prop extends DuskObject {
+
+       public int intImage;
+
+       public Prop(long lngID, String name) {
+               super(lngID, name);
+       }
+
+       @Override
+       public int getImage() {
+               return intImage;
+       }
+
+       @Override
+       public byte getType() {
+               return PROP;
+       }
+
+       @Override
+       public int getEntityType() {
+               return 3;
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/Sign.java b/DuskServer/src/duskz/server/entity/Sign.java
new file mode 100644 (file)
index 0000000..8753a99
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server.entity;
+
+import duskz.server.DuskEngine;
+
+/**
+ * Represents a sign object. A sign contains a string message and can be viewed
+ * by LivingThings.
+ *
+ * @author Tom Weingarten
+ */
+public class Sign extends DuskObject {
+
+       public String strMessage;
+       private final DuskEngine eng;
+
+       public Sign(DuskEngine eng, String name, String msg, int locx, int locy, long lngID) {
+               super(lngID, name);
+               strMessage = msg;
+               x = locx;
+               y = locy;
+               this.eng = eng;
+       }
+
+       @Override
+       public byte getType() {
+               return SIGN;
+       }
+
+       @Override
+       public int getImage() {
+               return eng.signimage;
+       }
+
+       @Override
+       public int getEntityType() {
+               return 3;
+       }
+}
diff --git a/DuskServer/src/duskz/server/entity/TileMap.java b/DuskServer/src/duskz/server/entity/TileMap.java
new file mode 100644 (file)
index 0000000..7d9d6cc
--- /dev/null
@@ -0,0 +1,740 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ */
+package duskz.server.entity;
+
+import duskz.util.Maths;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.PriorityQueue;
+
+/**
+ * Low level map management and helpers
+ *
+ * @author notzed
+ */
+public class TileMap implements Iterable<TileMap.MapData> {
+
+       private int rows, cols;
+       /**
+        * Tile map
+        */
+       private short tiles[];
+       /**
+        * Entities, they are chained off each other for efficiency reasons
+        */
+       private DuskObject entities[];
+       /**
+        * privileges for each cell. This appears to be unimplemented in Dusk so
+        * isn't here either.
+        */
+       protected short privs[];
+       /**
+        * Ownership for each cell. This appears to be unimplemented in Dusk so
+        * isn't here either.
+        */
+       protected int owner[];
+       /**
+        * Flags for iterators
+        */
+       public final static int SKIP_START = 1;
+       public final static int SKIP_END = 2;
+
+       /**
+        * Create a new empty map of the given size
+        *
+        * @param cols
+        * @param rows
+        */
+       public TileMap(int cols, int rows) {
+               this.rows = rows;
+               this.cols = cols;
+
+               tiles = new short[rows * cols];
+               entities = new DuskObject[rows * cols];
+       }
+
+       public int getRows() {
+               return rows;
+       }
+
+       public int getCols() {
+               return cols;
+       }
+
+       public void saveMap(File path) throws IOException {
+               path.delete();
+               try (RandomAccessFile rafFile = new RandomAccessFile(path, "rw")) {
+                       rafFile.writeInt(cols);
+                       rafFile.writeInt(rows);
+                       for (int x = 0; x < cols; x++) {
+                               for (int y = 0; y < rows; y++) {
+                                       rafFile.writeShort(getTile(x, y));
+                               }
+                       }
+               }
+       }
+       public static final int FORMAT_BYTE = 0;
+       public static final int FORMAT_SHORT = 1;
+
+       // Map in row major format (i.e. more efficient)
+       public static TileMap loadMapX(File path) throws IOException {
+               TileMap map;
+
+               try (DataInputStream mapFile = new DataInputStream(new FileInputStream(path))) {
+                       int cols = mapFile.readInt();
+                       int rows = mapFile.readInt();
+                       map = new TileMap(cols, rows);
+                       for (int y = 0; y < rows; y++) {
+                               for (int x = 0; x < cols; x++) {
+                                       map.setTile(x, y, mapFile.readShort());
+                               }
+                       }
+               }
+               return map;
+       }
+
+       public static TileMap loadMap(File path, int format) throws IOException {
+               TileMap map;
+
+               try (RandomAccessFile mapFile = new RandomAccessFile(path, "r")) {
+                       int cols = mapFile.readInt();
+                       int rows = mapFile.readInt();
+                       map = new TileMap(cols, rows);
+                       for (int x = 0; x < cols; x++) {
+                               for (int y = 0; y < rows; y++) {
+                                       if (format == FORMAT_BYTE)
+                                               map.setTile(x, y, mapFile.readByte());
+                                       else
+                                               map.setTile(x, y, mapFile.readShort());
+                               }
+                       }
+               }
+               return map;
+       }
+
+       /**
+        * Create a new map
+        *
+        * @param newcols
+        * @param newrows
+        * @return
+        */
+       public synchronized void resize(int newcols, int newrows) {
+               short[] ntiles = new short[newcols * newrows];
+               DuskObject[] nentities = new DuskObject[newcols * newrows];
+
+               int rx = Math.min(newcols, cols);
+               int ry = Math.min(newrows, rows);
+
+               for (int y = 0; y < ry; y++) {
+                       for (int x = 0; x < rx; x++) {
+                               int indexa = x + y * cols;
+                               int indexb = x + y * newcols;
+
+                               ntiles[indexb] = tiles[indexa];
+                               nentities[indexb] = entities[indexa];
+                       }
+               }
+
+               tiles = ntiles;
+               entities = nentities;
+               cols = newcols;
+               rows = newrows;
+       }
+
+       public boolean inside(int x, int y) {
+               return x >= 0 && x < cols
+                               && y >= 0 && y < rows;
+       }
+
+       public void setTile(int x, int y, int t) {
+               tiles[x + y * cols] = (short) t;
+       }
+
+       public short getTile(int x, int y) {
+               return tiles[x + y * cols];
+       }
+
+       public synchronized List<DuskObject> getEntities(int x, int y, List<DuskObject> list) {
+               if (list == null)
+                       list = new ArrayList<>();
+
+               DuskObject o = entities[x + y * cols];
+               while (o != null) {
+                       list.add(o);
+                       o = o.getNext();
+               }
+               return list;
+       }
+
+       public synchronized void addEntity(DuskObject o) {
+               if (inside(o.x, o.y)) {
+                       int index = o.x + o.y * cols;
+
+                       entities[index] = DuskObject.append(entities[index], o);
+               }
+       }
+
+       public synchronized void removeEntity(DuskObject o) {
+               if (inside(o.x, o.y)) {
+                       int index = o.x + o.y * cols;
+
+                       entities[index] = DuskObject.remove(entities[index], o);
+               }
+       }
+
+       /**
+        * Get an iterable over a range - allows foreach support
+        *
+        * @param x0
+        * @param y0
+        * @param x1
+        * @param y1
+        * @return
+        */
+       public Iterable<MapData> range(int x0, int y0, int x1, int y1) {
+               return new MapIterable(x0, y0, x1, y1);
+       }
+
+       /**
+        * Get an iterable over a range with a given centre and radius
+        *
+        * @param x
+        * @param y
+        * @param radius
+        * @return
+        */
+       public Iterable<MapData> range(int x, int y, int radius) {
+               return new MapIterable(x - radius, y - radius, x + radius + 1, y + radius + 1);
+       }
+
+       /**
+        * Get an iterable which will iterate over the looking path
+        *
+        * @param sx
+        * @param sy
+        * @param ex
+        * @param ey
+        * @param flags SKIP_END, SKIP_START to skip end/start locations
+        * (UNIMPLEMENTED)
+        * @return
+        */
+       public Iterable<MapData> look(int sx, int sy, int ex, int ey, int flags) {
+               return new LookIterable(sx, sy, ex, ey, flags);
+       }
+
+       public Iterable<MapData> look(int sx, int sy, int ex, int ey) {
+               return new LookIterable(sx, sy, ex, ey, 0);
+       }
+
+       public Iterable<MoveData> move(int sx, int sy, int ex, int ey, int flags, MoveListener l) {
+               return new MoveIterable(sx, sy, ex, ey, flags, l);
+       }
+
+       private class MapIterable implements Iterable<MapData> {
+
+               int x0, y0, x1, y1;
+
+               public MapIterable(int x0, int y0, int x1, int y1) {
+                       this.x0 = x0;
+                       this.y0 = y0;
+                       this.x1 = x1;
+                       this.y1 = y1;
+               }
+
+               @Override
+               public Iterator<MapData> iterator() {
+                       return new MapIterator(x0, y0, x1, y1);
+               }
+       }
+
+       private class LookIterable implements Iterable<MapData> {
+
+               int sx, sy, ex, ey;
+               int flags;
+
+               public LookIterable(int sx, int sy, int ex, int ey, int flags) {
+                       this.sx = sx;
+                       this.sy = sy;
+                       this.ex = ex;
+                       this.ey = ey;
+                       this.flags = flags;
+               }
+
+               @Override
+               public Iterator<MapData> iterator() {
+                       return new LookIterator(sx, sy, ex, ey, flags);
+               }
+       }
+
+       private class MoveIterable implements Iterable<MoveData> {
+
+               int sx, sy, ex, ey;
+               int flags;
+               MoveListener l;
+
+               public MoveIterable(int sx, int sy, int ex, int ey, int flags, MoveListener l) {
+                       this.sx = sx;
+                       this.sy = sy;
+                       this.ex = ex;
+                       this.ey = ey;
+                       this.flags = flags;
+                       this.l = l;
+               }
+
+               @Override
+               public Iterator<MoveData> iterator() {
+                       return new MoveIterator(sx, sy, ex, ey, flags, l);
+               }
+       }
+
+       public Iterator<MapData> getIterator(int x0, int y0, int x1, int y1) {
+               return new MapIterator(x0, y0, x1, y1);
+       }
+
+       @Override
+       public Iterator<MapData> iterator() {
+               return getIterator(0, 0, cols, rows);
+       }
+
+       public class MapData {
+
+               public int x, y;
+               public final List<DuskObject> entities = new ArrayList<>();
+               public short tile;
+
+               protected void setData(int x, int y) {
+                       this.x = x;
+                       this.y = y;
+                       this.entities.clear();
+                       if (inside(x, y)) {
+                               this.tile = getTile(x, y);
+                               getEntities(x, y, this.entities);
+                       } else {
+                               this.tile = 0;
+                       }
+               }
+       }
+
+       public class MoveData extends MapData {
+
+               public String direction;
+       }
+
+       private class MapIterator implements Iterator<MapData> {
+
+               int x0, y0, x1, y1;
+               int x, y;
+               MapData data = new MapData();
+
+               public MapIterator(int x0, int y0, int x1, int y1) {
+                       this.x0 = Maths.clamp(x0, 0, cols);
+                       this.y0 = Maths.clamp(y0, 0, rows);
+                       this.x1 = Maths.clamp(x1, 0, cols);
+                       this.y1 = Maths.clamp(y1, 0, rows);
+                       this.x = -1;
+                       this.y = -1;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       return (x + 1) < x1
+                                       || (y + 1) < y1;
+               }
+
+               @Override
+               public MapData next() {
+                       // FIXME: this needs to iterate in x first then y
+                       if (x == -1) {
+                               x = x0;
+                               y = y0;
+                       } else if (y + 1 < y1) {
+                               y++;
+                       } else {
+                               y = y0;
+                               x++;
+                       }
+
+                       data.setData(x, y);
+
+                       return data;
+               }
+
+               @Override
+               public void remove() {
+                       throw new UnsupportedOperationException("Not supported yet.");
+               }
+       }
+
+       /**
+        * Implements an iterator which follows a 'looking' path
+        *
+        * TODO: it should probably use Bresenhams line algorithm
+        */
+       private class LookIterator implements Iterator<MapData> {
+
+               int x, y;
+               final int sx, sy;
+               final int ex, ey;
+               int flags;
+               boolean there = false;
+               MapData data = new MapData();
+
+               public LookIterator(int sx, int sy, int ex, int ey, int flags) {
+                       this.x = sx;
+                       this.y = sy;
+                       this.sx = sx;
+                       this.sy = sy;
+                       this.ex = ex;
+                       this.ey = ey;
+                       this.flags = flags;
+
+                       diffx = Math.abs(ex - sx);
+                       diffy = Math.abs(ey - sy);
+                       stepx = Integer.signum(ex - sx);
+                       stepy = Integer.signum(ey - sy);
+                       err = diffx - diffy;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       return !there;
+               }
+               // Bresenham algorithm data, from wikipedia
+               int diffx, diffy;
+               int stepx, stepy;
+               int err;
+
+               void lineStep() {
+                       int e2 = 2 * err;
+                       if (e2 > -diffy) {
+                               err -= diffy;
+                               x += stepx;
+                       }
+                       if (e2 < diffx) {
+                               err += diffx;
+                               y += stepy;
+                       }
+               }
+
+               @Override
+               public MapData next() {
+                       there = x == ex && y == ey;
+
+                       // FIXME: impelement?
+                       //if ((flags & SKIP_START) != 0 && sx == x && sy == y) {
+                       //      lineStep();
+                       //}
+
+                       data.setData(x, y);
+
+                       if (!there) {
+                               lineStep();
+                       }
+                       return data;
+               }
+
+               public MapData nextOld() {
+                       there = x == ex && y == ey;
+
+                       data.setData(x, y);
+
+                       if (!there) {
+                               int stepx = Integer.signum(ex - y);
+                               int stepy = Integer.signum(ey - y);
+                               int dx = Math.abs(ex - x);
+                               int dy = Math.abs(ey - y);
+
+                               if (dx > dy) {
+                                       x += stepx;
+                               } else if (dx < dy) {
+                                       y += stepy;
+                               } else {
+                                       x += stepx;
+                                       y += stepy;
+                               }
+                       }
+
+                       return data;
+               }
+
+               @Override
+               public void remove() {
+                       throw new UnsupportedOperationException("Not supported yet.");
+               }
+       }
+
+       public interface MoveListener {
+
+               public boolean canMoveto(MapData md);
+       }
+
+       /**
+        * Iterator for movement.
+        */
+       private static class MoveInfo implements Comparable<MoveInfo> {
+
+               int x, y;
+               float cost;
+               float estimate;
+               String direction;
+               MoveInfo parent;
+
+               public MoveInfo(int x, int y, float cost, String direction) {
+                       this.x = x;
+                       this.y = y;
+                       this.cost = cost;
+                       this.direction = direction;
+               }
+
+               @Override
+               public boolean equals(Object obj) {
+                       MoveInfo o = (MoveInfo) obj;
+
+                       return x == o.x && y == o.y;
+               }
+
+               @Override
+               public int hashCode() {
+                       int hash = 5;
+                       hash = 59 * hash + this.x;
+                       hash = 59 * hash + this.y;
+                       return hash;
+               }
+
+               @Override
+               public int compareTo(MoveInfo o) {
+                       return Float.compare(cost, o.cost);
+               }
+       }
+
+       /**
+        * An iterator which steps through the individual moves to get to a
+        * destination.
+        *
+        * Implemented using A* algorithm, so can handle obstructions.
+        *
+        * TODO: Limit the search space.
+        */
+       private class MoveIterator implements Iterator<MoveData> {
+
+               int x, y;
+               final int sx, sy;
+               final int ex, ey;
+               int flags;
+               boolean there = false;
+               private final MoveListener l;
+               // quick hack version
+               Iterator<MoveInfo> iterator;
+               MoveData data = new MoveData();
+
+               public MoveIterator(int sx, int sy, int ex, int ey, int flags, MoveListener l) {
+                       this.x = sx;
+                       this.y = sy;
+                       this.sx = sx;
+                       this.sy = sy;
+                       this.ex = ex;
+                       this.ey = ey;
+                       this.flags = flags;
+                       this.l = l;
+
+                       // A* requires the whole path to be calculated ahead of time.
+
+                       List<MoveInfo> path = findPath();
+
+                       System.out.printf("Finding path from %d,%d to %d,%d: ", sx, sy, ex, ey);
+
+                       if (path != null) {
+                               for (MoveInfo mi : path) {
+                                       System.out.print(" ");
+                                       System.out.print(mi.direction);
+                               }
+                               System.out.println();
+
+                               if (!path.isEmpty() && (flags & SKIP_END) != 0) {
+                                       path.remove(path.size() - 1);
+                               }
+
+                               iterator = path.iterator();
+                       } else {
+                               System.out.println("No path found!");
+                       }
+               }
+
+               float estimateCost(int sx, int sy, int ex, int ey) {
+                       return (float) Math.sqrt((ex - sx) * (ex - sx) + (ey - sy) * (ey - sy));
+               }
+
+               List<MoveInfo> constructPath(List<MoveInfo> list, MoveInfo n) {
+                       if (list == null)
+                               list = new ArrayList<>();
+
+                       if (n.parent != null) {
+                               constructPath(list, n.parent);
+                               list.add(n);
+                       }
+
+                       return list;
+               }
+
+               void moveIf(List<MoveInfo> list, int x, int y, float cost, String dir) {
+                       data.setData(x, y);
+
+                       if (l.canMoveto(data)) {
+                               list.add(new MoveInfo(x, y, cost + 1, dir));
+                       }
+               }
+
+               List<MoveInfo> getNeighbours(MoveInfo n) {
+                       List<MoveInfo> list = new ArrayList<>(4);
+
+                       moveIf(list, n.x + 1, n.y, n.cost, "e");
+                       moveIf(list, n.x - 1, n.y, n.cost, "w");
+                       moveIf(list, n.x, n.y + 1, n.cost, "s");
+                       moveIf(list, n.x, n.y - 1, n.cost, "n");
+
+                       return list;
+               }
+
+               // A* algorithm from here:
+               //http://www.peachpit.com/articles/article.aspx?p=101142&seqNum=2
+               public List<MoveInfo> findPath() {
+
+                       PriorityQueue<MoveInfo> openList = new PriorityQueue();
+                       HashSet<MoveInfo> closedList = new HashSet<>();
+
+                       MoveInfo startNode = new MoveInfo(sx, sy, 0, null);
+                       startNode.estimate = estimateCost(sx, sy, ex, ey);
+                       startNode.parent = null;
+                       openList.add(startNode);
+
+                       while (!openList.isEmpty()) {
+                               MoveInfo node = openList.poll();
+                               if (node.x == ex && node.y == ey) {
+                                       // construct the path from start to goal
+                                       return constructPath(null, node);
+                               }
+
+                               List<MoveInfo> neighbors = getNeighbours(node);
+                               for (int i = 0; i < neighbors.size(); i++) {
+                                       MoveInfo nnode = neighbors.get(i);
+                                       boolean isOpen = openList.contains(nnode);
+                                       boolean isClosed = closedList.contains(nnode);
+                                       float costFromStart = node.cost + 1;
+
+                                       // check if the neighbor node has not been
+                                       // traversed or if a shorter path to this
+                                       // neighbor node is found.
+                                       if ((!isOpen && !isClosed)
+                                                       || costFromStart < nnode.cost) {
+                                               nnode.parent = node;
+                                               nnode.cost = costFromStart;
+                                               nnode.estimate = estimateCost(nnode.x, nnode.y, ex, ey);
+                                               if (isClosed) {
+                                                       closedList.remove(nnode);
+                                               }
+                                               if (!isOpen) {
+                                                       openList.add(nnode);
+                                               }
+                                       }
+                               }
+                               closedList.add(node);
+                       }
+
+                       // no path found
+                       return null;
+               }
+
+               @Override
+               public boolean hasNext() {
+                       if (iterator != null)
+                               return iterator.hasNext();
+                       else
+                               return false;
+               }
+
+               @Override
+               public MoveData next() {
+                       MoveInfo mi = iterator.next();
+
+                       data.setData(mi.x, mi.y);
+                       data.direction = mi.direction;
+
+                       return data;
+               }
+
+               @Override
+               public void remove() {
+                       throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+               }
+       }
+
+       public static void main(String[] args) {
+               TileMap map = new TileMap(16, 16);
+
+               /*
+                for (MapData md : map.look(5, 5, 10, 3)) {
+                System.out.printf(" %d,%d\n", md.x, md.y);
+                }
+                for (MapData md : map.look(15, 15, 0, 0)) {
+                System.out.printf(" %d,%d\n", md.x, md.y);
+                }
+                for (MapData md : map.look(15, 0, 0, 15)) {
+                System.out.printf(" %d,%d\n", md.x, md.y);
+                }*/
+
+
+               MoveListener l = new MoveListener() {
+                       @Override
+                       public boolean canMoveto(MapData md) {
+                               //System.out.printf("can move %d,%d\n", md.x, md.y);
+                               return md.tile == 0;
+                       }
+               };
+               System.out.println("no obstacles");
+               for (MoveData md : map.move(0, 0, 10, 10, 0, l)) {
+                       System.out.printf(" %d,%d %s\n", md.x, md.y, md.direction);
+               }
+
+               // put an obstacle in the way
+               for (int x = 0; x < 11; x++) {
+                       map.setTile(x, 5, 1);
+               }
+               System.out.println("line in the way");
+               for (MoveData md : map.move(0, 0, 10, 10, SKIP_END, l)) {
+                       System.out.printf(" %d,%d %s\n", md.x, md.y, md.direction);
+               }
+               System.out.println("line in the way to last");
+               for (MoveData md : map.move(0, 0, 1, 1, 0, l)) {
+                       System.out.printf(" %d,%d %s\n", md.x, md.y, md.direction);
+               }
+
+       }
+}
diff --git a/DuskZ/COPYING b/DuskZ/COPYING
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is 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.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  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.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  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 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. Use with the GNU Affero General Public License.
+
+  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 Affero 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 special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 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 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 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 General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  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 GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/DuskZ/COPYING.GPLv2 b/DuskZ/COPYING.GPLv2
new file mode 100644 (file)
index 0000000..d159169
--- /dev/null
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  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
+this service 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.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+                     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
+convey 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 General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/DuskZ/README b/DuskZ/README
new file mode 100644 (file)
index 0000000..5ab7274
--- /dev/null
@@ -0,0 +1,44 @@
+
+README
+------
+This is the client frontend to DuskZ, it uses JavaFX.  It connects
+to the DuskServer togehter and requires some local data installed.
+
+It is a fork and major overhaul of the Dusk 2.7.3 source code, released
+circa 2000.
+
+Currently a recent Oracle JRE is required to execute this application.
+
+This is currently in an alpha state and in very active development.
+
+ ... to be completed ...
+
+INSTALLATION
+------------
+ ... to be completed ...
+
+RUNNING
+-------
+ ... to be completed ...
+
+LICENSE
+-------
+  DuskZ is free software, see COPYING for your rights.
+
+  Some files are under other compatible licenses.
+
+  Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+  Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+
+  DuskZ is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  DuskZ is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/DuskZ/build.xml b/DuskZ/build.xml
new file mode 100644 (file)
index 0000000..0d44bda
--- /dev/null
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?><!-- You may freely edit this file. See commented blocks below for --><!-- some examples of how to customize the build. --><!-- (If you delete it and reopen the project it will be recreated.) --><!-- By default, only the Clean and Build commands use this build script. --><project name="DuskZ" default="default" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant">
+    <description>Builds, tests, and runs the project DuskZ.</description>
+    <import file="nbproject/build-impl.xml"/>
+    <!--
+
+    There exist several targets which are by default empty and which can be 
+    used for execution of your tasks. These targets are usually executed 
+    before and after some main targets. Those of them relevant for JavaFX project are: 
+
+      -pre-init:                 called before initialization of project properties
+      -post-init:                called after initialization of project properties
+      -pre-compile:              called before javac compilation
+      -post-compile:             called after javac compilation
+      -pre-compile-test:         called before javac compilation of JUnit tests
+      -post-compile-test:        called after javac compilation of JUnit tests
+      -pre-jfx-jar:              called before FX SDK specific <fx:jar> task
+      -post-jfx-jar:             called after FX SDK specific <fx:jar> task
+      -pre-jfx-deploy:           called before FX SDK specific <fx:deploy> task
+      -post-jfx-deploy:          called after FX SDK specific <fx:deploy> task
+      -pre-jfx-native:           called just after -pre-jfx-deploy if <fx:deploy> runs in native packaging mode
+      -post-jfx-native:          called just after -post-jfx-deploy if <fx:deploy> runs in native packaging mode
+      -post-clean:               called after cleaning build products
+
+    (Targets beginning with '-' are not intended to be called on their own.)
+
+    Example of inserting a HTML postprocessor after javaFX SDK deployment:
+
+        <target name="-post-jfx-deploy">
+            <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
+            <property name="jfx.deployment.html" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}.html"/>
+            <custompostprocess>
+                <fileset dir="${jfx.deployment.html}"/>
+            </custompostprocess>
+        </target>
+
+    Example of calling an Ant task from JavaFX SDK. Note that access to JavaFX SDK Ant tasks must be
+    initialized; to ensure this is done add the dependence on -check-jfx-sdk-version target:
+
+        <target name="-post-jfx-jar" depends="-check-jfx-sdk-version">
+            <echo message="Calling jar task from JavaFX SDK"/>
+            <fx:jar ...>
+                ...
+            </fx:jar>
+        </target>
+
+    For more details about JavaFX SDK Ant tasks go to
+    http://docs.oracle.com/javafx/2/deployment/jfxpub-deployment.htm
+
+    For list of available properties check the files
+    nbproject/build-impl.xml and nbproject/jfx-impl.xml.
+
+    -->
+</project>
diff --git a/DuskZ/manifest.mf b/DuskZ/manifest.mf
new file mode 100644 (file)
index 0000000..328e8e5
--- /dev/null
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+X-COMMENT: Main-Class will be added automatically by build
+
diff --git a/DuskZ/nbproject/build-impl.xml b/DuskZ/nbproject/build-impl.xml
new file mode 100644 (file)
index 0000000..467fa6e
--- /dev/null
@@ -0,0 +1,1459 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM project.xml - DO NOT EDIT  ***
+***         EDIT ../build.xml INSTEAD         ***
+
+For the purpose of easier reading the script
+is divided into following sections:
+
+  - initialization
+  - compilation
+  - jar
+  - execution
+  - debugging
+  - javadoc
+  - test compilation
+  - test execution
+  - test debugging
+  - applet
+  - cleanup
+
+        -->
+<project xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:jaxrpc="http://www.netbeans.org/ns/j2se-project/jax-rpc" basedir=".." default="default" name="DuskZ-impl">
+    <import file="jfx-impl.xml"/>
+    <fail message="Please build using Ant 1.8.0 or higher.">
+        <condition>
+            <not>
+                <antversion atleast="1.8.0"/>
+            </not>
+        </condition>
+    </fail>
+    <target depends="test,jar,javadoc" description="Build and test whole project." name="default"/>
+    <!-- 
+                ======================
+                INITIALIZATION SECTION 
+                ======================
+            -->
+    <target name="-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init" name="-init-private">
+        <property file="nbproject/private/config.properties"/>
+        <property file="nbproject/private/configs/${config}.properties"/>
+        <property file="nbproject/private/private.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private" name="-init-user">
+        <property file="${user.properties.file}"/>
+        <!-- The two properties below are usually overridden -->
+        <!-- by the active platform. Just a fallback. -->
+        <property name="default.javac.source" value="1.4"/>
+        <property name="default.javac.target" value="1.4"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user" name="-init-project">
+        <property file="nbproject/configs/${config}.properties"/>
+        <property file="nbproject/project.properties"/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-init-macrodef-property" name="-do-init">
+        <j2seproject1:property name="platform.home" value="platforms.${platform.active}.home"/>
+        <j2seproject1:property name="platform.bootcp" value="platforms.${platform.active}.bootclasspath"/>
+        <j2seproject1:property name="platform.compiler" value="platforms.${platform.active}.compile"/>
+        <j2seproject1:property name="platform.javac.tmp" value="platforms.${platform.active}.javac"/>
+        <condition property="platform.javac" value="${platform.home}/bin/javac">
+            <equals arg1="${platform.javac.tmp}" arg2="$${platforms.${platform.active}.javac}"/>
+        </condition>
+        <property name="platform.javac" value="${platform.javac.tmp}"/>
+        <j2seproject1:property name="platform.java.tmp" value="platforms.${platform.active}.java"/>
+        <condition property="platform.java" value="${platform.home}/bin/java">
+            <equals arg1="${platform.java.tmp}" arg2="$${platforms.${platform.active}.java}"/>
+        </condition>
+        <property name="platform.java" value="${platform.java.tmp}"/>
+        <j2seproject1:property name="platform.javadoc.tmp" value="platforms.${platform.active}.javadoc"/>
+        <condition property="platform.javadoc" value="${platform.home}/bin/javadoc">
+            <equals arg1="${platform.javadoc.tmp}" arg2="$${platforms.${platform.active}.javadoc}"/>
+        </condition>
+        <property name="platform.javadoc" value="${platform.javadoc.tmp}"/>
+        <condition property="platform.invalid" value="true">
+            <or>
+                <contains string="${platform.javac}" substring="$${platforms."/>
+                <contains string="${platform.java}" substring="$${platforms."/>
+                <contains string="${platform.javadoc}" substring="$${platforms."/>
+            </or>
+        </condition>
+        <fail unless="platform.home">Must set platform.home</fail>
+        <fail unless="platform.bootcp">Must set platform.bootcp</fail>
+        <fail unless="platform.java">Must set platform.java</fail>
+        <fail unless="platform.javac">Must set platform.javac</fail>
+        <fail if="platform.invalid">
+ The J2SE Platform is not correctly set up.
+ Your active platform is: ${platform.active}, but the corresponding property "platforms.${platform.active}.home" is not found in the project's properties files. 
+ Either open the project in the IDE and setup the Platform with the same name or add it manually.
+ For example like this:
+     ant -Duser.properties.file=&lt;path_to_property_file&gt; jar (where you put the property "platforms.${platform.active}.home" in a .properties file)
+  or ant -Dplatforms.${platform.active}.home=&lt;path_to_JDK_home&gt; jar (where no properties file is used) 
+  </fail>
+        <available file="${manifest.file}" property="manifest.available"/>
+        <condition property="splashscreen.available">
+            <and>
+                <not>
+                    <equals arg1="${application.splash}" arg2="" trim="true"/>
+                </not>
+                <available file="${application.splash}"/>
+            </and>
+        </condition>
+        <condition property="main.class.available">
+            <and>
+                <isset property="main.class"/>
+                <not>
+                    <equals arg1="${main.class}" arg2="" trim="true"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class">
+            <and>
+                <isset property="manifest.available"/>
+                <isset property="main.class.available"/>
+            </and>
+        </condition>
+        <condition property="do.archive">
+            <not>
+                <istrue value="${jar.archive.disabled}"/>
+            </not>
+        </condition>
+        <condition property="do.mkdist">
+            <and>
+                <isset property="do.archive"/>
+                <isset property="libs.CopyLibs.classpath"/>
+                <not>
+                    <istrue value="${mkdist.disabled}"/>
+                </not>
+            </and>
+        </condition>
+        <condition property="manifest.available+main.class+mkdist.available">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available">
+            <and>
+                <isset property="manifest.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+main.class.available">
+            <and>
+                <isset property="main.class.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+splashscreen.available">
+            <and>
+                <isset property="splashscreen.available"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="do.archive+manifest.available+main.class">
+            <and>
+                <istrue value="${manifest.available+main.class}"/>
+                <istrue value="${do.archive}"/>
+            </and>
+        </condition>
+        <condition property="manifest.available-mkdist.available">
+            <or>
+                <istrue value="${manifest.available}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="manifest.available+main.class-mkdist.available">
+            <or>
+                <istrue value="${manifest.available+main.class}"/>
+                <isset property="do.mkdist"/>
+            </or>
+        </condition>
+        <condition property="have.tests">
+            <or>
+                <available file="${test.src.dir}"/>
+            </or>
+        </condition>
+        <condition property="have.sources">
+            <or>
+                <available file="${src.dir}"/>
+            </or>
+        </condition>
+        <condition property="netbeans.home+have.tests">
+            <and>
+                <isset property="netbeans.home"/>
+                <isset property="have.tests"/>
+            </and>
+        </condition>
+        <condition property="no.javadoc.preview">
+            <and>
+                <isset property="javadoc.preview"/>
+                <isfalse value="${javadoc.preview}"/>
+            </and>
+        </condition>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>
+        <property name="javac.compilerargs" value=""/>
+        <property name="work.dir" value="${basedir}"/>
+        <condition property="no.deps">
+            <and>
+                <istrue value="${no.dependencies}"/>
+            </and>
+        </condition>
+        <property name="javac.debug" value="true"/>
+        <property name="javadoc.preview" value="true"/>
+        <property name="application.args" value=""/>
+        <property name="source.encoding" value="${file.encoding}"/>
+        <property name="runtime.encoding" value="${source.encoding}"/>
+        <condition property="javadoc.encoding.used" value="${javadoc.encoding}">
+            <and>
+                <isset property="javadoc.encoding"/>
+                <not>
+                    <equals arg1="${javadoc.encoding}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <property name="javadoc.encoding.used" value="${source.encoding}"/>
+        <property name="includes" value="**"/>
+        <property name="excludes" value=""/>
+        <property name="do.depend" value="false"/>
+        <condition property="do.depend.true">
+            <istrue value="${do.depend}"/>
+        </condition>
+        <path id="endorsed.classpath.path" path="${endorsed.classpath}"/>
+        <condition else="" property="endorsed.classpath.cmd.line.arg" value="-Xbootclasspath/p:'${toString:endorsed.classpath.path}'">
+            <length length="0" string="${endorsed.classpath}" when="greater"/>
+        </condition>
+        <property name="jar.index" value="false"/>
+        <property name="jar.index.metainf" value="${jar.index}"/>
+        <property name="copylibs.rebase" value="true"/>
+        <available file="${meta.inf.dir}/persistence.xml" property="has.persistence.xml"/>
+        <condition property="junit.available">
+            <or>
+                <available classname="org.junit.Test" classpath="${run.test.classpath}"/>
+                <available classname="junit.framework.Test" classpath="${run.test.classpath}"/>
+            </or>
+        </condition>
+        <condition property="testng.available">
+            <available classname="org.testng.annotations.Test" classpath="${run.test.classpath}"/>
+        </condition>
+        <condition property="junit+testng.available">
+            <and>
+                <istrue value="${junit.available}"/>
+                <istrue value="${testng.available}"/>
+            </and>
+        </condition>
+        <condition else="testng" property="testng.mode" value="mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+        <condition else="" property="testng.debug.mode" value="-mixed">
+            <istrue value="${junit+testng.available}"/>
+        </condition>
+    </target>
+    <target name="-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-check-javafx" name="-init-check">
+        <fail unless="src.dir">Must set src.dir</fail>
+        <fail unless="test.src.dir">Must set test.src.dir</fail>
+        <fail unless="build.dir">Must set build.dir</fail>
+        <fail unless="dist.dir">Must set dist.dir</fail>
+        <fail unless="build.classes.dir">Must set build.classes.dir</fail>
+        <fail unless="dist.javadoc.dir">Must set dist.javadoc.dir</fail>
+        <fail unless="build.test.classes.dir">Must set build.test.classes.dir</fail>
+        <fail unless="build.test.results.dir">Must set build.test.results.dir</fail>
+        <fail unless="build.classes.excludes">Must set build.classes.excludes</fail>
+        <fail unless="dist.jar">Must set dist.jar</fail>
+    </target>
+    <target name="-init-macrodef-property">
+        <macrodef name="property" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${@{value}}"/>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <mkdir dir="@{apgeneratedsrcdir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" executable="${platform.javac}" fork="yes" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <compilerarg value="-processorpath"/>
+                    <compilerarg path="@{processorpath}:${empty.dir}"/>
+                    <compilerarg line="${ap.processors.internal}"/>
+                    <compilerarg line="${annotation.processing.processor.options}"/>
+                    <compilerarg value="-s"/>
+                    <compilerarg path="@{apgeneratedsrcdir}"/>
+                    <compilerarg line="${ap.proc.none.internal}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
+        <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <attribute default="${javac.processorpath}" name="processorpath"/>
+            <attribute default="${build.generated.sources.dir}/ap-source-output" name="apgeneratedsrcdir"/>
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="${javac.debug}" name="debug"/>
+            <attribute default="${empty.dir}" name="sourcepath"/>
+            <attribute default="${empty.dir}" name="gensrcdir"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.dir}/empty" name="empty.dir"/>
+                <mkdir dir="${empty.dir}"/>
+                <javac debug="@{debug}" deprecation="${javac.deprecation}" destdir="@{destdir}" encoding="${source.encoding}" excludes="@{excludes}" executable="${platform.javac}" fork="yes" includeantruntime="false" includes="@{includes}" source="${javac.source}" sourcepath="@{sourcepath}" srcdir="@{srcdir}" target="${javac.target}" tempdir="${java.io.tmpdir}">
+                    <src>
+                        <dirset dir="@{gensrcdir}" erroronmissingdir="false">
+                            <include name="*"/>
+                        </dirset>
+                    </src>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <compilerarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <compilerarg line="${javac.compilerargs}"/>
+                    <customize/>
+                </javac>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
+        <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${src.dir}" name="srcdir"/>
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <attribute default="${javac.classpath}" name="classpath"/>
+            <sequential>
+                <depend cache="${build.dir}/depcache" destdir="@{destdir}" excludes="${excludes}" includes="${includes}" srcdir="@{srcdir}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                </depend>
+            </sequential>
+        </macrodef>
+        <macrodef name="force-recompile" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${build.classes.dir}" name="destdir"/>
+            <sequential>
+                <fail unless="javac.includes">Must set javac.includes</fail>
+                <pathconvert pathsep="${line.separator}" property="javac.includes.binary">
+                    <path>
+                        <filelist dir="@{destdir}" files="${javac.includes}"/>
+                    </path>
+                    <globmapper from="*.java" to="*.class"/>
+                </pathconvert>
+                <tempfile deleteonexit="true" property="javac.includesfile.binary"/>
+                <echo file="${javac.includesfile.binary}" message="${javac.includes.binary}"/>
+                <delete>
+                    <files includesfile="${javac.includesfile.binary}"/>
+                </delete>
+                <delete>
+                    <fileset file="${javac.includesfile.binary}"/>
+                </delete>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-init">
+        <condition else="false" property="nb.junit.batch" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <not>
+                    <isset property="test.method"/>
+                </not>
+            </and>
+        </condition>
+        <condition else="false" property="nb.junit.single" value="true">
+            <and>
+                <istrue value="${junit.available}"/>
+                <isset property="test.method"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-init-test-properties">
+        <property name="test.binaryincludes" value="&lt;nothing&gt;"/>
+        <property name="test.binarytestincludes" value=""/>
+        <property name="test.binaryexcludes" value=""/>
+    </target>
+    <target if="${nb.junit.single}" name="-init-macrodef-junit-single" unless="${nb.junit.batch}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-batch" unless="${nb.junit.single}">
+        <macrodef name="junit" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-init,-init-macrodef-junit-single, -init-macrodef-junit-batch" if="${junit.available}" name="-init-macrodef-junit"/>
+    <target if="${testng.available}" name="-init-macrodef-testng">
+        <macrodef name="testng" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <condition else="" property="testng.methods.arg" value="@{testincludes}.@{testmethods}">
+                    <isset property="test.method"/>
+                </condition>
+                <union id="test.set">
+                    <fileset dir="${test.src.dir}" excludes="@{excludes},**/*.xml,${excludes}" includes="@{includes}">
+                        <filename name="@{testincludes}"/>
+                    </fileset>
+                </union>
+                <taskdef classname="org.testng.TestNGAntTask" classpath="${run.test.classpath}" name="testng"/>
+                <testng classfilesetref="test.set" failureProperty="tests.failed" jvm="${platform.java}" methods="${testng.methods.arg}" mode="${testng.mode}" outputdir="${build.test.results.dir}" suitename="DuskZ" testname="TestNG tests" workingDir="${work.dir}">
+                    <xmlfileset dir="${build.test.classes.dir}" includes="@{testincludes}"/>
+                    <propertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </propertyset>
+                    <customize/>
+                </testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-test-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <echo>No tests executed.</echo>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit" if="${junit.available}" name="-init-macrodef-junit-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng" if="${testng.available}" name="-init-macrodef-testng-impl">
+        <macrodef name="test-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:testng excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:testng>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-impl,-init-macrodef-junit-impl,-init-macrodef-testng-impl" name="-init-macrodef-test">
+        <macrodef name="test" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <sequential>
+                <j2seproject3:test-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${junit.available}" name="-init-macrodef-junit-debug" unless="${nb.junit.batch}">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}">
+                    <test methods="@{testmethods}" name="@{testincludes}" todir="${build.test.results.dir}"/>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-test-properties" if="${nb.junit.batch}" name="-init-macrodef-junit-debug-batch">
+        <macrodef name="junit-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property name="junit.forkmode" value="perTest"/>
+                <junit dir="${work.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" forkmode="${junit.forkmode}" jvm="${platform.java}" showoutput="true" tempdir="${build.dir}">
+                    <batchtest todir="${build.test.results.dir}">
+                        <fileset dir="${test.src.dir}" excludes="@{excludes},${excludes}" includes="@{includes}">
+                            <filename name="@{testincludes}"/>
+                        </fileset>
+                        <fileset dir="${build.test.classes.dir}" excludes="@{excludes},${excludes},${test.binaryexcludes}" includes="${test.binaryincludes}">
+                            <filename name="${test.binarytestincludes}"/>
+                        </fileset>
+                    </batchtest>
+                    <syspropertyset>
+                        <propertyref prefix="test-sys-prop."/>
+                        <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <formatter type="brief" usefile="false"/>
+                    <formatter type="xml"/>
+                    <jvmarg value="-ea"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <customize/>
+                </junit>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug,-init-macrodef-junit-debug-batch" if="${junit.available}" name="-init-macrodef-junit-debug-impl">
+        <macrodef name="test-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <element implicit="true" name="customize" optional="true"/>
+            <sequential>
+                <j2seproject3:junit-debug excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize/>
+                </j2seproject3:junit-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target if="${testng.available}" name="-init-macrodef-testng-debug">
+        <macrodef name="testng-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element name="customize2" optional="true"/>
+            <sequential>
+                <condition else="-testclass @{testClass}" property="test.class.or.method" value="-methods @{testClass}.@{testMethod}">
+                    <isset property="test.method"/>
+                </condition>
+                <condition else="-suitename DuskZ -testname @{testClass} ${test.class.or.method}" property="testng.cmd.args" value="@{testClass}">
+                    <matches pattern=".*\.xml" string="@{testClass}"/>
+                </condition>
+                <delete dir="${build.test.results.dir}" quiet="true"/>
+                <mkdir dir="${build.test.results.dir}"/>
+                <j2seproject3:debug classname="org.testng.TestNG" classpath="${debug.test.classpath}">
+                    <customize>
+                        <customize2/>
+                        <jvmarg value="-ea"/>
+                        <arg line="${testng.debug.mode}"/>
+                        <arg line="-d ${build.test.results.dir}"/>
+                        <arg line="-listener org.testng.reporters.VerboseReporter"/>
+                        <arg line="${testng.cmd.args}"/>
+                    </customize>
+                </j2seproject3:debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug" if="${testng.available}" name="-init-macrodef-testng-debug-impl">
+        <macrodef name="testng-debug-impl" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <element implicit="true" name="customize2" optional="true"/>
+            <sequential>
+                <j2seproject3:testng-debug testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2/>
+                </j2seproject3:testng-debug>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-junit-debug-impl" if="${junit.available}" name="-init-macrodef-test-debug-junit">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:test-debug-impl excludes="@{excludes}" includes="@{includes}" testincludes="@{testincludes}" testmethods="@{testmethods}">
+                    <customize>
+                        <classpath>
+                            <path path="${run.test.classpath}"/>
+                        </classpath>
+                        <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                        <jvmarg line="${run.jvmargs}"/>
+                        <jvmarg line="${run.jvmargs.ide}"/>
+                    </customize>
+                </j2seproject3:test-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-testng-debug-impl" if="${testng.available}" name="-init-macrodef-test-debug-testng">
+        <macrodef name="test-debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${includes}" name="includes"/>
+            <attribute default="${excludes}" name="excludes"/>
+            <attribute default="**" name="testincludes"/>
+            <attribute default="" name="testmethods"/>
+            <attribute default="${main.class}" name="testClass"/>
+            <attribute default="" name="testMethod"/>
+            <sequential>
+                <j2seproject3:testng-debug-impl testClass="@{testClass}" testMethod="@{testMethod}">
+                    <customize2>
+                        <syspropertyset>
+                            <propertyref prefix="test-sys-prop."/>
+                            <mapper from="test-sys-prop.*" to="*" type="glob"/>
+                        </syspropertyset>
+                    </customize2>
+                </j2seproject3:testng-debug-impl>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-init-macrodef-test-debug-junit,-init-macrodef-test-debug-testng" name="-init-macrodef-test-debug"/>
+    <!--
+                pre NB7.2 profiling section; consider it deprecated
+            -->
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile, -profile-init-check" if="profiler.info.jvmargs.agent" name="profile-init"/>
+    <target if="profiler.info.jvmargs.agent" name="-profile-pre-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-post-init">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="profiler.info.jvmargs.agent" name="-profile-init-macrodef-profile">
+        <macrodef name="resolve">
+            <attribute name="name"/>
+            <attribute name="value"/>
+            <sequential>
+                <property name="@{name}" value="${env.@{value}}"/>
+            </sequential>
+        </macrodef>
+        <macrodef name="profile">
+            <attribute default="${main.class}" name="classname"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property environment="env"/>
+                <resolve name="profiler.current.path" value="${profiler.info.pathvar}"/>
+                <java classname="@{classname}" dir="${profiler.info.dir}" fork="true" jvm="${profiler.info.jvm}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="${profiler.info.jvmargs.agent}"/>
+                    <jvmarg line="${profiler.info.jvmargs}"/>
+                    <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+                    <arg line="${application.args}"/>
+                    <classpath>
+                        <path path="${run.classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target depends="-profile-pre-init, init, -profile-post-init, -profile-init-macrodef-profile" if="profiler.info.jvmargs.agent" name="-profile-init-check">
+        <fail unless="profiler.info.jvm">Must set JVM to use for profiling in profiler.info.jvm</fail>
+        <fail unless="profiler.info.jvmargs.agent">Must set profiler agent JVM arguments in profiler.info.jvmargs.agent</fail>
+    </target>
+    <!--
+                end of pre NB7.2 profiling section
+            -->
+    <target depends="-init-debug-args" name="-init-macrodef-nbjpda">
+        <macrodef name="nbjpdastart" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="name"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <attribute default="" name="stopclassname"/>
+            <sequential>
+                <nbjpdastart addressproperty="jpda.address" name="@{name}" stopclassname="@{stopclassname}" transport="${debug-transport}">
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <bootclasspath>
+                        <path path="${platform.bootcp}"/>
+                    </bootclasspath>
+                </nbjpdastart>
+            </sequential>
+        </macrodef>
+        <macrodef name="nbjpdareload" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${build.classes.dir}" name="dir"/>
+            <sequential>
+                <nbjpdareload>
+                    <fileset dir="@{dir}" includes="${fix.classes}">
+                        <include name="${fix.includes}*.class"/>
+                    </fileset>
+                </nbjpdareload>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-debug-args">
+        <exec executable="${platform.java}" outputproperty="version-output">
+            <arg value="-version"/>
+        </exec>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+    <target depends="-init-debug-args" name="-init-macrodef-debug">
+        <macrodef name="debug" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${debug.classpath}" name="classpath"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true" jvm="${platform.java}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg line="${debug-args-line}"/>
+                    <jvmarg value="-Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-java">
+        <macrodef name="java" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <attribute default="${main.class}" name="classname"/>
+            <attribute default="${run.classpath}" name="classpath"/>
+            <attribute default="jvm" name="jvm"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <java classname="@{classname}" dir="${work.dir}" fork="true" jvm="${platform.java}">
+                    <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+                    <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+                    <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+                    <jvmarg line="${run.jvmargs}"/>
+                    <jvmarg line="${run.jvmargs.ide}"/>
+                    <classpath>
+                        <path path="@{classpath}"/>
+                    </classpath>
+                    <syspropertyset>
+                        <propertyref prefix="run-sys-prop."/>
+                        <mapper from="run-sys-prop.*" to="*" type="glob"/>
+                    </syspropertyset>
+                    <customize/>
+                </java>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-macrodef-copylibs">
+        <macrodef name="copylibs" uri="http://www.netbeans.org/ns/j2se-project/3">
+            <attribute default="${manifest.file}" name="manifest"/>
+            <element name="customize" optional="true"/>
+            <sequential>
+                <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+                <pathconvert property="run.classpath.without.build.classes.dir">
+                    <path path="${run.classpath}"/>
+                    <map from="${build.classes.dir.resolved}" to=""/>
+                </pathconvert>
+                <pathconvert pathsep=" " property="jar.classpath">
+                    <path path="${run.classpath.without.build.classes.dir}"/>
+                    <chainedmapper>
+                        <flattenmapper/>
+                        <filtermapper>
+                            <replacestring from=" " to="%20"/>
+                        </filtermapper>
+                        <globmapper from="*" to="lib/*"/>
+                    </chainedmapper>
+                </pathconvert>
+                <taskdef classname="org.netbeans.modules.java.j2seproject.copylibstask.CopyLibs" classpath="${libs.CopyLibs.classpath}" name="copylibs"/>
+                <copylibs compress="${jar.compress}" index="${jar.index}" indexMetaInf="${jar.index.metainf}" jarfile="${dist.jar}" manifest="@{manifest}" rebase="${copylibs.rebase}" runtimeclasspath="${run.classpath.without.build.classes.dir}">
+                    <fileset dir="${build.classes.dir}"/>
+                    <manifest>
+                        <attribute name="Class-Path" value="${jar.classpath}"/>
+                        <customize/>
+                    </manifest>
+                </copylibs>
+            </sequential>
+        </macrodef>
+    </target>
+    <target name="-init-presetdef-jar">
+        <presetdef name="jar" uri="http://www.netbeans.org/ns/j2se-project/1">
+            <jar compress="${jar.compress}" index="${jar.index}" jarfile="${dist.jar}">
+                <j2seproject1:fileset dir="${build.classes.dir}"/>
+            </jar>
+        </presetdef>
+    </target>
+    <target name="-init-ap-cmdline-properties">
+        <property name="annotation.processing.enabled" value="true"/>
+        <property name="annotation.processing.processors.list" value=""/>
+        <property name="annotation.processing.processor.options" value=""/>
+        <property name="annotation.processing.run.all.processors" value="true"/>
+        <property name="javac.processorpath" value="${javac.classpath}"/>
+        <property name="javac.test.processorpath" value="${javac.test.classpath}"/>
+        <condition property="ap.supported.internal" value="true">
+            <not>
+                <matches pattern="1\.[0-5](\..*)?" string="${javac.source}"/>
+            </not>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-ap-cmdline-supported">
+        <condition else="" property="ap.processors.internal" value="-processor ${annotation.processing.processors.list}">
+            <isfalse value="${annotation.processing.run.all.processors}"/>
+        </condition>
+        <condition else="" property="ap.proc.none.internal" value="-proc:none">
+            <isfalse value="${annotation.processing.enabled}"/>
+        </condition>
+    </target>
+    <target depends="-init-ap-cmdline-properties,-init-ap-cmdline-supported" name="-init-ap-cmdline">
+        <property name="ap.cmd.line.internal" value=""/>
+    </target>
+    <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init,-post-init,-init-check,-init-macrodef-property,-init-macrodef-javac,-init-macrodef-test,-init-macrodef-test-debug,-init-macrodef-nbjpda,-init-macrodef-debug,-init-macrodef-java,-init-presetdef-jar,-init-ap-cmdline" name="init"/>
+    <!--
+                ===================
+                COMPILATION SECTION
+                ===================
+            -->
+    <target name="-deps-jar-init" unless="built-jar.properties">
+        <property location="${build.dir}/built-jar.properties" name="built-jar.properties"/>
+        <delete file="${built-jar.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.jar.${basedir}" name="-warn-already-built-jar">
+        <echo level="warn" message="Cycle detected: DuskZ was already built"/>
+    </target>
+    <target depends="init,-deps-jar-init" name="deps-jar" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-jar.properties}" verbose="false"/>
+        <property file="${built-jar.properties}" prefix="already.built.jar."/>
+        <antcall target="-warn-already-built-jar"/>
+        <propertyfile file="${built-jar.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-jar.properties}"/>
+            <param location="${project.DuskCommon}" name="call.subproject"/>
+            <param location="${project.DuskCommon}/build.xml" name="call.script"/>
+            <param name="call.target" value="jar"/>
+            <param name="transfer.built-jar.properties" value="${built-jar.properties}"/>
+        </antcall>
+    </target>
+    <target depends="init,-check-automatic-build,-clean-after-automatic-build" name="-verify-automatic-build"/>
+    <target depends="init" name="-check-automatic-build">
+        <available file="${build.classes.dir}/.netbeans_automatic_build" property="netbeans.automatic.build"/>
+    </target>
+    <target depends="init" if="netbeans.automatic.build" name="-clean-after-automatic-build">
+        <antcall target="clean"/>
+    </target>
+    <target depends="init,deps-jar" name="-pre-pre-compile">
+        <mkdir dir="${build.classes.dir}"/>
+    </target>
+    <target name="-pre-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-depend">
+        <pathconvert property="build.generated.subdirs">
+            <dirset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="*"/>
+            </dirset>
+        </pathconvert>
+        <j2seproject3:depend srcdir="${src.dir}:${build.generated.subdirs}"/>
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
+        <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
+        <copy todir="${build.classes.dir}">
+            <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target if="has.persistence.xml" name="-copy-persistence-xml">
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy todir="${build.classes.dir}/META-INF">
+            <fileset dir="${meta.inf.dir}" includes="persistence.xml orm.xml"/>
+        </copy>
+    </target>
+    <target name="-post-compile">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile,-do-compile,-post-compile" description="Compile project." name="compile"/>
+    <target name="-pre-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile/>
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.dir}"/>
+    </target>
+    <target name="-post-compile-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,-verify-automatic-build,-pre-pre-compile,-pre-compile-single,-do-compile-single,-post-compile-single" name="compile-single"/>
+    <!--
+                ====================
+                JAR BUILDING SECTION
+                ====================
+            -->
+    <target depends="init" name="-pre-pre-jar">
+        <dirname file="${dist.jar}" property="dist.jar.dir"/>
+        <mkdir dir="${dist.jar.dir}"/>
+    </target>
+    <target name="-pre-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive" name="-do-jar-without-manifest" unless="manifest.available-mkdist.available">
+        <j2seproject1:jar/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available" name="-do-jar-with-manifest" unless="manifest.available+main.class-mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}"/>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar" if="do.archive+manifest.available+main.class" name="-do-jar-with-mainclass" unless="manifest.available+main.class+mkdist.available">
+        <j2seproject1:jar manifest="${manifest.file}">
+            <j2seproject1:manifest>
+                <j2seproject1:attribute name="Main-Class" value="${main.class}"/>
+            </j2seproject1:manifest>
+        </j2seproject1:jar>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${build.classes.dir}" name="build.classes.dir.resolved"/>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <pathconvert property="run.classpath.with.dist.jar">
+            <path path="${run.classpath}"/>
+            <map from="${build.classes.dir.resolved}" to="${dist.jar.resolved}"/>
+        </pathconvert>
+        <echo level="info">${platform.java} -cp "${run.classpath.with.dist.jar}" ${main.class}</echo>
+    </target>
+    <target depends="init" if="do.archive" name="-do-jar-with-libraries-create-manifest" unless="manifest.available">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <touch file="${tmp.manifest.file}" verbose="false"/>
+    </target>
+    <target depends="init" if="do.archive+manifest.available" name="-do-jar-with-libraries-copy-manifest">
+        <tempfile deleteonexit="true" destdir="${build.dir}" property="tmp.manifest.file"/>
+        <copy file="${manifest.file}" tofile="${tmp.manifest.file}"/>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+main.class.available" name="-do-jar-with-libraries-set-main">
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="Main-Class" value="${main.class}"/>
+        </manifest>
+    </target>
+    <target depends="init,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest" if="do.archive+splashscreen.available" name="-do-jar-with-libraries-set-splashscreen">
+        <basename file="${application.splash}" property="splashscreen.basename"/>
+        <mkdir dir="${build.classes.dir}/META-INF"/>
+        <copy failonerror="false" file="${application.splash}" todir="${build.classes.dir}/META-INF"/>
+        <manifest file="${tmp.manifest.file}" mode="update">
+            <attribute name="SplashScreen-Image" value="META-INF/${splashscreen.basename}"/>
+        </manifest>
+    </target>
+    <target depends="init,-init-macrodef-copylibs,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen" if="do.mkdist" name="-do-jar-with-libraries-pack">
+        <j2seproject3:copylibs manifest="${tmp.manifest.file}"/>
+        <echo level="info">To run this application from the command line without Ant, try:</echo>
+        <property location="${dist.jar}" name="dist.jar.resolved"/>
+        <echo level="info">${platform.java} -jar "${dist.jar.resolved}"</echo>
+    </target>
+    <target depends="-do-jar-with-libraries-pack" if="do.archive" name="-do-jar-with-libraries-delete-manifest">
+        <delete>
+            <fileset file="${tmp.manifest.file}"/>
+        </delete>
+    </target>
+    <target depends="init,compile,-pre-pre-jar,-pre-jar,-do-jar-with-libraries-create-manifest,-do-jar-with-libraries-copy-manifest,-do-jar-with-libraries-set-main,-do-jar-with-libraries-set-splashscreen,-do-jar-with-libraries-pack,-do-jar-with-libraries-delete-manifest" name="-do-jar-with-libraries"/>
+    <target depends="-jfx-copylibs,-rebase-libs,jfx-deployment" name="-post-jar">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-jar,-do-jar-with-manifest,-do-jar-without-manifest,-do-jar-with-mainclass,-do-jar-with-libraries,-post-jar,-jfx-copylibs,-rebase-libs" description="Build JAR." name="jar"/>
+    <!--
+                =================
+                EXECUTION SECTION
+                =================
+            -->
+    <target depends="init,compile,jar" description="Run a main class." name="run">
+        <j2seproject1:java>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <target name="-do-not-recompile">
+        <property name="javac.includes.binary" value=""/>
+    </target>
+    <target depends="init,compile-single" name="run-single">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}"/>
+    </target>
+    <target depends="init,compile-test-single" name="run-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <j2seproject1:java classname="${run.class}" classpath="${run.test.classpath}"/>
+    </target>
+    <!--
+                =================
+                DEBUGGING SECTION
+                =================
+            -->
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger">
+        <j2seproject1:nbjpdastart name="${debug.class}"/>
+    </target>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-main-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${debug.class}"/>
+    </target>
+    <target depends="init,compile" name="-debug-start-debuggee">
+        <j2seproject3:debug>
+            <customize>
+                <arg line="${application.args}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile,-debug-start-debugger,-debug-start-debuggee,jar" description="Debug project in IDE." if="netbeans.home" name="debug"/>
+    <target depends="init" if="netbeans.home" name="-debug-start-debugger-stepinto">
+        <j2seproject1:nbjpdastart stopclassname="${main.class}"/>
+    </target>
+    <target depends="init,compile,-debug-start-debugger-stepinto,-debug-start-debuggee" if="netbeans.home" name="debug-stepinto"/>
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-single">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}"/>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-single" if="netbeans.home" name="debug-single"/>
+    <target depends="init,compile-test-single" if="netbeans.home" name="-debug-start-debuggee-main-test">
+        <fail unless="debug.class">Must select one file in the IDE or set debug.class</fail>
+        <j2seproject3:debug classname="${debug.class}" classpath="${debug.test.classpath}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-main-test,-debug-start-debuggee-main-test" if="netbeans.home" name="debug-test-with-main"/>
+    <target depends="init" name="-pre-debug-fix">
+        <fail unless="fix.includes">Must set fix.includes</fail>
+        <property name="javac.includes" value="${fix.includes}.java"/>
+    </target>
+    <target depends="init,-pre-debug-fix,compile-single" if="netbeans.home" name="-do-debug-fix">
+        <j2seproject1:nbjpdareload/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix" if="netbeans.home" name="debug-fix"/>
+    <!--
+                =================
+                PROFILING SECTION
+                =================
+            -->
+    <!--
+                pre NB7.2 profiler integration
+            -->
+    <target depends="profile-init,compile" description="Profile a project in the IDE." if="profiler.info.jvmargs.agent" name="-profile-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile/>
+    </target>
+    <target depends="profile-init,compile-single" description="Profile a selected class in the IDE." if="profiler.info.jvmargs.agent" name="-profile-single-pre72">
+        <fail unless="profile.class">Must select one file in the IDE or set profile.class</fail>
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="${profile.class}"/>
+    </target>
+    <target depends="profile-init,compile-single" if="profiler.info.jvmargs.agent" name="-profile-applet-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <profile classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </profile>
+    </target>
+    <target depends="profile-init,compile-test-single" if="profiler.info.jvmargs.agent" name="-profile-test-single-pre72">
+        <fail unless="netbeans.home">This target only works when run from inside the NetBeans IDE.</fail>
+        <nbprofiledirect>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+        </nbprofiledirect>
+        <junit dir="${profiler.info.dir}" errorproperty="tests.failed" failureproperty="tests.failed" fork="true" jvm="${profiler.info.jvm}" showoutput="true">
+            <env key="${profiler.info.pathvar}" path="${profiler.info.agentpath}:${profiler.current.path}"/>
+            <jvmarg value="${profiler.info.jvmargs.agent}"/>
+            <jvmarg line="${profiler.info.jvmargs}"/>
+            <test name="${profile.class}"/>
+            <classpath>
+                <path path="${run.test.classpath}"/>
+            </classpath>
+            <syspropertyset>
+                <propertyref prefix="test-sys-prop."/>
+                <mapper from="test-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+            <formatter type="brief" usefile="false"/>
+            <formatter type="xml"/>
+        </junit>
+    </target>
+    <!--
+                end of pre NB72 profiling section
+            -->
+    <target if="netbeans.home" name="-profile-check">
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    <target depends="-profile-check,-profile-pre72,jar" description="Profile a project in the IDE." if="profiler.configured" name="profile" unless="profiler.info.jvmargs.agent">
+        <startprofiler/>
+        <antcall target="run"/>
+    </target>
+    <target depends="-profile-check,-profile-single-pre72" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-single" unless="profiler.info.jvmargs.agent">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcall target="run-single"/>
+    </target>
+    <target depends="-profile-test-single-pre72" description="Profile a selected test in the IDE." name="profile-test-single"/>
+    <target depends="-profile-check" description="Profile a selected test in the IDE." if="profiler.configured" name="profile-test" unless="profiler.info.jvmargs">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <startprofiler/>
+        <antcall target="test-single"/>
+    </target>
+    <target depends="-profile-check" description="Profile a selected class in the IDE." if="profiler.configured" name="profile-test-with-main">
+        <fail unless="run.class">Must select one file in the IDE or set run.class</fail>
+        <startprofiler/>
+        <antcal target="run-test-with-main"/>
+    </target>
+    <target depends="-profile-check,-profile-applet-pre72" if="profiler.configured" name="profile-applet" unless="profiler.info.jvmargs.agent">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <startprofiler/>
+        <antcall target="run-applet"/>
+    </target>
+    <!--
+                ===============
+                JAVADOC SECTION
+                ===============
+            -->
+    <target depends="init" if="have.sources" name="-javadoc-build">
+        <mkdir dir="${dist.javadoc.dir}"/>
+        <condition else="" property="javadoc.endorsed.classpath.cmd.line.arg" value="-J${endorsed.classpath.cmd.line.arg}">
+            <and>
+                <isset property="endorsed.classpath.cmd.line.arg"/>
+                <not>
+                    <equals arg1="${endorsed.classpath.cmd.line.arg}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <javadoc additionalparam="${javadoc.additionalparam}" author="${javadoc.author}" charset="UTF-8" destdir="${dist.javadoc.dir}" docencoding="UTF-8" encoding="${javadoc.encoding.used}" executable="${platform.javadoc}" failonerror="true" noindex="${javadoc.noindex}" nonavbar="${javadoc.nonavbar}" notree="${javadoc.notree}" private="${javadoc.private}" source="${javac.source}" splitindex="${javadoc.splitindex}" use="${javadoc.use}" useexternalfile="true" version="${javadoc.version}" windowtitle="${javadoc.windowtitle}">
+            <classpath>
+                <path path="${javac.classpath}"/>
+            </classpath>
+            <fileset dir="${src.dir}" excludes="*.java,${excludes}" includes="${includes}">
+                <filename name="**/*.java"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/*.java"/>
+                <exclude name="*.java"/>
+            </fileset>
+            <arg line="${javadoc.endorsed.classpath.cmd.line.arg}"/>
+        </javadoc>
+        <copy todir="${dist.javadoc.dir}">
+            <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
+                <filename name="**/doc-files/**"/>
+            </fileset>
+            <fileset dir="${build.generated.sources.dir}" erroronmissingdir="false">
+                <include name="**/doc-files/**"/>
+            </fileset>
+        </copy>
+    </target>
+    <target depends="init,-javadoc-build" if="netbeans.home" name="-javadoc-browse" unless="no.javadoc.preview">
+        <nbbrowse file="${dist.javadoc.dir}/index.html"/>
+    </target>
+    <target depends="init,-javadoc-build,-javadoc-browse" description="Build Javadoc." name="javadoc"/>
+    <!--
+                =========================
+                TEST COMPILATION SECTION
+                =========================
+            -->
+    <target depends="init,compile" if="have.tests" name="-pre-pre-compile-test">
+        <mkdir dir="${build.test.classes.dir}"/>
+    </target>
+    <target name="-pre-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target if="do.depend.true" name="-compile-test-depend">
+        <j2seproject3:depend classpath="${javac.test.classpath}" destdir="${build.test.classes.dir}" srcdir="${test.src.dir}"/>
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test,-compile-test-depend" if="have.tests" name="-do-compile-test">
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" processorpath="${javac.test.processorpath}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test,-do-compile-test,-post-compile-test" name="compile-test"/>
+    <target name="-pre-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-jar,compile,-pre-pre-compile-test,-pre-compile-test-single" if="have.tests" name="-do-compile-test-single">
+        <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
+        <j2seproject3:force-recompile destdir="${build.test.classes.dir}"/>
+        <j2seproject3:javac apgeneratedsrcdir="${build.test.classes.dir}" classpath="${javac.test.classpath}" debug="true" destdir="${build.test.classes.dir}" excludes="" includes="${javac.includes}" processorpath="${javac.test.processorpath}" sourcepath="${test.src.dir}" srcdir="${test.src.dir}"/>
+        <copy todir="${build.test.classes.dir}">
+            <fileset dir="${test.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
+        </copy>
+    </target>
+    <target name="-post-compile-test-single">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,compile,-pre-pre-compile-test,-pre-compile-test-single,-do-compile-test-single,-post-compile-test-single" name="compile-test-single"/>
+    <!--
+                =======================
+                TEST EXECUTION SECTION
+                =======================
+            -->
+    <target depends="init" if="have.tests" name="-pre-test-run">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run" if="have.tests" name="-do-test-run">
+        <j2seproject3:test testincludes="**/*Test.java"/>
+    </target>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run" if="have.tests" name="-post-test-run">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init" if="have.tests" name="test-report"/>
+    <target depends="init" if="netbeans.home+have.tests" name="-test-browse"/>
+    <target depends="init,compile-test,-pre-test-run,-do-test-run,test-report,-post-test-run,-test-browse" description="Run unit tests." name="test"/>
+    <target depends="init" if="have.tests" name="-pre-test-run-single">
+        <mkdir dir="${build.test.results.dir}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single">
+        <fail unless="test.includes">Must select some files in the IDE or set test.includes</fail>
+        <j2seproject3:test excludes="" includes="${test.includes}" testincludes="${test.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single" if="have.tests" name="-post-test-run-single">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single,-post-test-run-single" description="Run single unit test." name="test-single"/>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-do-test-run-single-method">
+        <fail unless="test.class">Must select some files in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test excludes="" includes="${javac.includes}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method" if="have.tests" name="-post-test-run-single-method">
+        <fail if="tests.failed" unless="ignore.failing.tests">Some tests failed; see details above.</fail>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single,-do-test-run-single-method,-post-test-run-single-method" description="Run single unit test." name="test-single-method"/>
+    <!--
+                =======================
+                TEST DEBUGGING SECTION
+                =======================
+            -->
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testincludes="${javac.includes}"/>
+    </target>
+    <target depends="init,compile-test-single,-pre-test-run-single" if="have.tests" name="-debug-start-debuggee-test-method">
+        <fail unless="test.class">Must select one file in the IDE or set test.class</fail>
+        <fail unless="test.method">Must select some method in the IDE or set test.method</fail>
+        <j2seproject3:test-debug excludes="" includes="${javac.includes}" testClass="${test.class}" testMethod="${test.method}" testincludes="${test.class}" testmethods="${test.method}"/>
+    </target>
+    <target depends="init,compile-test" if="netbeans.home+have.tests" name="-debug-start-debugger-test">
+        <j2seproject1:nbjpdastart classpath="${debug.test.classpath}" name="${test.class}"/>
+    </target>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test" name="debug-test"/>
+    <target depends="init,compile-test-single,-debug-start-debugger-test,-debug-start-debuggee-test-method" name="debug-test-method"/>
+    <target depends="init,-pre-debug-fix,compile-test-single" if="netbeans.home" name="-do-debug-fix-test">
+        <j2seproject1:nbjpdareload dir="${build.test.classes.dir}"/>
+    </target>
+    <target depends="init,-pre-debug-fix,-do-debug-fix-test" if="netbeans.home" name="debug-fix-test"/>
+    <!--
+                =========================
+                APPLET EXECUTION SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" name="run-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject1:java classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject1:java>
+    </target>
+    <!--
+                =========================
+                APPLET DEBUGGING  SECTION
+                =========================
+            -->
+    <target depends="init,compile-single" if="netbeans.home" name="-debug-start-debuggee-applet">
+        <fail unless="applet.url">Must select one file in the IDE or set applet.url</fail>
+        <j2seproject3:debug classname="sun.applet.AppletViewer">
+            <customize>
+                <arg value="${applet.url}"/>
+            </customize>
+        </j2seproject3:debug>
+    </target>
+    <target depends="init,compile-single,-debug-start-debugger,-debug-start-debuggee-applet" if="netbeans.home" name="debug-applet"/>
+    <!--
+                ===============
+                CLEANUP SECTION
+                ===============
+            -->
+    <target name="-deps-clean-init" unless="built-clean.properties">
+        <property location="${build.dir}/built-clean.properties" name="built-clean.properties"/>
+        <delete file="${built-clean.properties}" quiet="true"/>
+    </target>
+    <target if="already.built.clean.${basedir}" name="-warn-already-built-clean">
+        <echo level="warn" message="Cycle detected: DuskZ was already built"/>
+    </target>
+    <target depends="init,-deps-clean-init" name="deps-clean" unless="no.deps">
+        <mkdir dir="${build.dir}"/>
+        <touch file="${built-clean.properties}" verbose="false"/>
+        <property file="${built-clean.properties}" prefix="already.built.clean."/>
+        <antcall target="-warn-already-built-clean"/>
+        <propertyfile file="${built-clean.properties}">
+            <entry key="${basedir}" value=""/>
+        </propertyfile>
+        <antcall target="-maybe-call-dep">
+            <param name="call.built.properties" value="${built-clean.properties}"/>
+            <param location="${project.DuskCommon}" name="call.subproject"/>
+            <param location="${project.DuskCommon}/build.xml" name="call.script"/>
+            <param name="call.target" value="clean"/>
+            <param name="transfer.built-clean.properties" value="${built-clean.properties}"/>
+        </antcall>
+    </target>
+    <target depends="init" name="-do-clean">
+        <delete dir="${build.dir}"/>
+        <delete dir="${dist.dir}" followsymlinks="false" includeemptydirs="true"/>
+    </target>
+    <target name="-post-clean">
+        <!-- Empty placeholder for easier customization. -->
+        <!-- You can override this target in the ../build.xml file. -->
+    </target>
+    <target depends="init,deps-clean,-do-clean,-post-clean" description="Clean build products." name="clean"/>
+    <target name="-check-call-dep">
+        <property file="${call.built.properties}" prefix="already.built."/>
+        <condition property="should.call.dep">
+            <and>
+                <not>
+                    <isset property="already.built.${call.subproject}"/>
+                </not>
+                <available file="${call.script}"/>
+            </and>
+        </condition>
+    </target>
+    <target depends="-check-call-dep" if="should.call.dep" name="-maybe-call-dep">
+        <ant antfile="${call.script}" inheritall="false" target="${call.target}">
+            <propertyset>
+                <propertyref prefix="transfer."/>
+                <mapper from="transfer.*" to="*" type="glob"/>
+            </propertyset>
+        </ant>
+    </target>
+</project>
diff --git a/DuskZ/nbproject/configs/Run_as_WebStart.properties b/DuskZ/nbproject/configs/Run_as_WebStart.properties
new file mode 100644 (file)
index 0000000..670fff0
--- /dev/null
@@ -0,0 +1,2 @@
+# Do not modify this property in this configuration. It can be re-generated.
+$label=Run as WebStart
diff --git a/DuskZ/nbproject/configs/Run_in_Browser.properties b/DuskZ/nbproject/configs/Run_in_Browser.properties
new file mode 100644 (file)
index 0000000..f2a5a65
--- /dev/null
@@ -0,0 +1,2 @@
+# Do not modify this property in this configuration. It can be re-generated.
+$label=Run in Browser
diff --git a/DuskZ/nbproject/genfiles.properties b/DuskZ/nbproject/genfiles.properties
new file mode 100644 (file)
index 0000000..a6ee1b3
--- /dev/null
@@ -0,0 +1,8 @@
+build.xml.data.CRC32=be5f771c
+build.xml.script.CRC32=d9af4be0
+build.xml.stylesheet.CRC32=28e38971@1.56.1.46
+# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
+# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
+nbproject/build-impl.xml.data.CRC32=46d0094e
+nbproject/build-impl.xml.script.CRC32=21080c51
+nbproject/build-impl.xml.stylesheet.CRC32=c6d2a60f@1.56.1.46
diff --git a/DuskZ/nbproject/jfx-impl.xml b/DuskZ/nbproject/jfx-impl.xml
new file mode 100644 (file)
index 0000000..43adba7
--- /dev/null
@@ -0,0 +1,3218 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+*** GENERATED FROM TEMPLATE - DO NOT EDIT ***
+***       EDIT ../build.xml INSTEAD       ***
+-->
+
+<project name="jfx-impl" default="jfx-deployment" basedir=".." xmlns:j2seproject1="http://www.netbeans.org/ns/j2se-project/1" 
+         xmlns:j2seproject3="http://www.netbeans.org/ns/j2se-project/3" xmlns:fx="javafx:com.sun.javafx.tools.ant">
+    <description>JavaFX-specific Ant calls</description>
+
+
+    <!-- Empty placeholders for easier customization in ../build.xml -->
+    
+    <target name="-pre-jfx-jar">
+        <!-- Called right before <fx:jar> task. You can override this target in the ../build.xml file. -->
+    </target>
+
+    <target name="-post-jfx-jar">
+        <!-- Called right after <fx:jar> task. You can override this target in the ../build.xml file. -->
+    </target>
+
+    <target name="-pre-jfx-deploy">
+        <!-- Called right before <fx:deploy> task. You can override this target in the ../build.xml file. -->
+    </target>
+
+    <target name="-post-jfx-deploy">
+        <!-- Called right after <fx:deploy> task. You can override this target in the ../build.xml file. -->
+    </target>
+    
+    <target name="-pre-jfx-native">
+        <!-- Called right before the call to native packager (just after -pre-jfx-deploy). You can override this target in the ../build.xml file. -->
+    </target>
+
+    <target name="-post-jfx-native">
+        <!-- Called right after the call to native packager (just after -post-jfx-deploy). You can override this target in the ../build.xml file. -->
+    </target>
+    
+    
+    <!-- Check system and JDK version -->
+
+    <target name="-check-operating-system">
+        <condition property="running.on.mac">
+            <os family="mac"/>
+        </condition>
+        <condition property="running.on.unix">
+            <os family="unix"/>
+        </condition>
+        <condition property="running.on.windows">
+            <os family="windows"/>
+        </condition>
+        <echo message="running.on.mac = ${running.on.mac}" level="verbose"/>
+        <echo message="running.on.unix = ${running.on.unix}" level="verbose"/>
+        <echo message="running.on.windows = ${running.on.windows}" level="verbose"/>
+    </target>
+
+    <target name="-check-platform-home-fxsdk-java" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.platform.home.fxsdk.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${javafx.sdk}${file.separator}bin${file.separator}java"/>
+                    <available file="${javafx.sdk}${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-fxsdk-java" depends="-check-platform-home-fxsdk-java" if="do.set.platform.home.fxsdk.java">
+        <property name="active.platform.home.java.executable" value="${javafx.sdk}${file.separator}bin${file.separator}java"/>
+    </target>
+    <target name="-check-platform-home-java" if="platform.home">
+        <condition property="do.set.platform.home.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${platform.home}${file.separator}bin${file.separator}java"/>
+                    <available file="${platform.home}${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-java" depends="-set-platform-home-fxsdk-java,-check-platform-home-java" if="do.set.platform.home.java">
+        <property name="active.platform.home.java.executable" value="${platform.home}${file.separator}bin${file.separator}java"/>
+    </target>
+    <target name="-check-platform-home-probjdk-java" unless="active.platform.home.java.executable">
+        <condition property="do.set.platform.home.probjdk.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${java.home}${file.separator}..${file.separator}bin${file.separator}java"/>
+                    <available file="${java.home}${file.separator}..${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-probjdk-java" depends="-set-platform-home-java,-check-platform-home-probjdk-java" if="do.set.platform.home.probjdk.java">
+        <property name="active.platform.home.java.executable" value="${java.home}${file.separator}..${file.separator}bin${file.separator}java"/>
+    </target>
+    <target name="-check-platform-home-envjdk-java" unless="active.platform.home.java.executable">
+        <property environment="env"/>
+        <condition property="do.set.platform.home.envjdk.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${env.JAVA_HOME}${file.separator}bin${file.separator}java"/>
+                    <available file="${env.JAVA_HOME}${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-envjdk-java" depends="-set-platform-home-probjdk-java,-check-platform-home-envjdk-java" if="do.set.platform.home.envjdk.java">
+        <property environment="env"/>
+        <property name="active.platform.home.java.executable" value="${env.JAVA_HOME}${file.separator}bin${file.separator}java"/>
+    </target>
+    <target name="-check-platform-home-fxrt-java" depends="-check-property-javafx.runtime" if="javafx.runtime.defined">
+        <condition property="do.set.platform.home.fxrt.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${javafx.runtime}${file.separator}bin${file.separator}java"/>
+                    <available file="${javafx.runtime}${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-fxrt-java" depends="-set-platform-home-envjdk-java,-check-platform-home-fxrt-java" if="do.set.platform.home.fxrt.java">
+        <property name="active.platform.home.java.executable" value="${javafx.runtime}${file.separator}bin${file.separator}java"/>
+        <echo message="Warning: java executable not found in JDK, evaluating java executable in RT instead." level="info"/>
+    </target>
+    <target name="-check-platform-home-jre-java" unless="active.platform.home.java.executable">
+        <condition property="do.set.platform.home.jre.java">
+            <and>
+                <not><isset property="active.platform.home.java.executable"/></not>
+                <or>
+                    <available file="${java.home}${file.separator}bin${file.separator}java"/>
+                    <available file="${java.home}${file.separator}bin${file.separator}java.exe"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-platform-home-jre-java" depends="-set-platform-home-fxrt-java,-check-platform-home-jre-java" if="do.set.platform.home.jre.java">
+        <property name="active.platform.home.java.executable" value="${java.home}${file.separator}bin${file.separator}java"/>
+        <echo message="Warning: java executable not found in JDK, evaluating java executable in RT instead." level="info"/>
+    </target>
+    <target name="-check-platform-home" depends="-set-platform-home-jre-java">
+        <echo message="active.platform.home.java.executable = ${active.platform.home.java.executable}" level="verbose"/>
+        <fail message="Error:${line.separator}java executable not found !" unless="active.platform.home.java.executable"/>
+    </target>
+        
+    <target name="-check-jdk-version" depends="-do-init,-check-platform-home" unless="jdk-version-checked-in-jfximpl">
+        <local name="version-output"/>
+        <exec executable="${active.platform.home.java.executable}" outputproperty="version-output">
+            <arg value="-version"/>
+        </exec>
+        <echo message="version-output:${line.separator}${version-output}" level="verbose"/>
+        <condition property="have-jdk-older-than-1.6">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+                <contains string="${version-output}" substring="java version &quot;1.4"/>
+                <contains string="${version-output}" substring="java version &quot;1.5"/>
+            </or>
+        </condition>
+        <fail message="Error:${line.separator}JavaFX 2.0+ projects require JDK version 1.6+ !" if="have-jdk-older-than-1.6"/>
+        <condition property="have-jdk-7u4or5-mac">
+            <and>
+                <or>
+                    <contains string="${version-output}" substring="java version &quot;1.7.0_04"/>
+                    <contains string="${version-output}" substring="java version &quot;1.7.0_05"/>
+                </or>
+                <os family="mac"/>
+            </and>
+        </condition>
+        <condition property="have-jdk-pre7u6">
+            <or>
+                <isset property="have-jdk-older-than-1.6"/>
+                <contains string="${version-output}" substring="java version &quot;1.6"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0&quot;"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_01"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_02"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_03"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_04"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_05"/>
+            </or>
+        </condition>
+        <condition property="have-jdk7-css2bin-bug">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_04"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_05"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_06"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_07"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_08"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_09"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_10"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_11"/>
+            </or>
+        </condition>
+        <property name="jdk-version-checked-in-jfximpl" value="true"/>
+        <echo message="have-jdk-7u4or5-mac = ${have-jdk-7u4or5-mac}" level="verbose"/>
+        <echo message="have-jdk-pre7u6 = ${have-jdk-pre7u6}" level="verbose"/>
+        <echo message="have-jdk7-css2bin-bug = ${have-jdk7-css2bin-bug}" level="verbose"/>
+    </target>
+        
+    <target name="-check-ant-jre-version" unless="ant-jre-version-checked-in-jfximpl">
+        <local name="version-output"/>
+        <exec executable="${java.home}${file.separator}bin${file.separator}java" outputproperty="version-output">
+            <arg value="-version"/>
+        </exec>
+        <echo message="version-output:${line.separator}${version-output}" level="verbose"/>
+        <condition property="have-ant-jre-pre7u6">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+                <contains string="${version-output}" substring="java version &quot;1.4"/>
+                <contains string="${version-output}" substring="java version &quot;1.5"/>
+                <contains string="${version-output}" substring="java version &quot;1.6"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0&quot;"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_01"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_02"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_03"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_04"/>
+                <contains string="${version-output}" substring="java version &quot;1.7.0_05"/>
+            </or>
+        </condition>
+        <property name="ant-jre-version-checked-in-jfximpl" value="true"/>
+        <echo message="have-ant-jre-pre7u6 = ${have-ant-jre-pre7u6}" level="verbose"/>
+    </target>
+
+    <target name="-check-jdk-7u4or5-mac" depends="-check-jdk-version" if="have-jdk-7u4or5-mac">
+        <fail message="Error:${line.separator}JDK 7u4 Mac and 7u5 Mac do not support WebStart and JavaFX 2.0+ browser plugin technologies.${line.separator}Please upgrade to JDK 7u6 or later."/>
+    </target>
+
+    
+    <!-- Check availability of JavaFX SDK deployment support (ant-javafx.jar) -->
+
+    <target name="-check-endorsed-javafx-ant-classpath">
+        <condition property="endorsed-javafx-ant-classpath-available">
+            <and>
+                <isset property="endorsed.javafx.ant.classpath"/>
+                <not>
+                    <equals arg1="${endorsed.javafx.ant.classpath}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <echo message="endorsed-javafx-ant-classpath-available = ${endorsed-javafx-ant-classpath-available}" level="verbose"/>
+    </target>
+
+    <target name="-check-property-javafx.sdk">
+        <echo message="javafx.sdk = ${javafx.sdk}" level="verbose"/>
+        <condition property="javafx.sdk.defined">
+            <and>
+                <isset property="javafx.sdk"/>
+                <not><contains string="${javafx.sdk}" substring="$${platform" casesensitive="false"/></not>
+            </and>
+        </condition>
+        <condition property="javafx.sdk.missing+default">
+            <and>
+                <equals arg1="${platform.active}" arg2="Default_JavaFX_Platform" trim="true"/>
+                <not><isset property="javafx.sdk.defined"/></not>
+            </and>
+        </condition>
+        <condition property="javafx.sdk.missing-default">
+            <and>
+                <not><equals arg1="${platform.active}" arg2="Default_JavaFX_Platform" trim="true"/></not>
+                <not><isset property="javafx.sdk.defined"/></not>
+            </and>
+        </condition>
+        <echo message="javafx.sdk.defined = ${javafx.sdk.defined}" level="verbose"/>
+        <echo message="javafx.sdk.missing+default = ${javafx.sdk.missing+default}" level="verbose"/>
+        <echo message="javafx.sdk.missing-default = ${javafx.sdk.missing-default}" level="verbose"/>
+    </target>
+
+    <target name="-check-ant-javafx-in-fxsdk-lib" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.ant-javafx.in.fxsdk.lib">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${javafx.sdk}${file.separator}lib${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-fxsdk-lib" depends="-check-ant-javafx-in-fxsdk-lib" if="do.set.ant-javafx.in.fxsdk.lib">
+        <property name="ant-javafx.jar.location" value="${javafx.sdk}${file.separator}lib${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-fxsdk-tools" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.ant-javafx.in.fxsdk.tools">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${javafx.sdk}${file.separator}tools${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-fxsdk-tools" depends="-set-ant-javafx-in-fxsdk-lib,-check-ant-javafx-in-fxsdk-tools" if="do.set.ant-javafx.in.fxsdk.tools">
+        <property name="ant-javafx.jar.location" value="${javafx.sdk}${file.separator}tools${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-platform-home-lib" if="platform.home">
+        <condition property="do.set.ant-javafx.in.platform.home.lib">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${platform.home}${file.separator}lib${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-platform-home-lib" depends="-set-ant-javafx-in-fxsdk-tools,-check-ant-javafx-in-platform-home-lib" if="do.set.ant-javafx.in.platform.home.lib">
+        <property name="ant-javafx.jar.location" value="${platform.home}${file.separator}lib${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-platform-home-tools" if="platform.home">
+        <condition property="do.set.ant-javafx.in.platform.home.tools">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${platform.home}${file.separator}tools${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-platform-home-tools" depends="-set-ant-javafx-in-platform-home-lib,-check-ant-javafx-in-platform-home-tools" if="do.set.ant-javafx.in.platform.home.tools">
+        <property name="ant-javafx.jar.location" value="${platform.home}${file.separator}tools${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-probjdk-lib" unless="ant-javafx.jar.location">
+        <condition property="do.set.ant-javafx.in.probjdk.lib">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${java.home}${file.separator}..${file.separator}lib${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-probjdk-lib" depends="-set-ant-javafx-in-platform-home-tools,-check-ant-javafx-in-probjdk-lib" if="do.set.ant-javafx.in.probjdk.lib">
+        <property name="ant-javafx.jar.location" value="${java.home}${file.separator}..${file.separator}lib${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-probjdk-tools" unless="ant-javafx.jar.location">
+        <condition property="do.set.ant-javafx.in.probjdk.tools">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${java.home}${file.separator}..${file.separator}tools${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-probjdk-tools" depends="-set-ant-javafx-in-probjdk-lib,-check-ant-javafx-in-probjdk-tools" if="do.set.ant-javafx.in.probjdk.tools">
+        <property name="ant-javafx.jar.location" value="${java.home}${file.separator}..${file.separator}tools${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-macjdk-lib" unless="ant-javafx.jar.location">
+        <condition property="do.set.ant-javafx.in.macjdk.lib">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${java.home}${file.separator}lib${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-macjdk-lib" depends="-set-ant-javafx-in-probjdk-tools,-check-ant-javafx-in-macjdk-lib" if="do.set.ant-javafx.in.macjdk.lib">
+        <property name="ant-javafx.jar.location" value="${java.home}${file.separator}lib${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-envjdk-lib" unless="ant-javafx.jar.location">
+        <property environment="env"/>
+        <condition property="do.set.ant-javafx.in.envjdk.lib">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${env.JAVA_HOME}${file.separator}lib${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-envjdk-lib" depends="-set-ant-javafx-in-macjdk-lib,-check-ant-javafx-in-envjdk-lib" if="do.set.ant-javafx.in.envjdk.lib">
+        <property name="ant-javafx.jar.location" value="${env.JAVA_HOME}${file.separator}lib${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-check-ant-javafx-in-envjdk-tools" unless="ant-javafx.jar.location">
+        <property environment="env"/>
+        <condition property="do.set.ant-javafx.in.envjdk.tools">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${env.JAVA_HOME}${file.separator}tools${file.separator}ant-javafx.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-ant-javafx-in-envjdk-tools" depends="-set-ant-javafx-in-envjdk-lib,-check-ant-javafx-in-envjdk-tools" if="do.set.ant-javafx.in.envjdk.tools">
+        <property name="ant-javafx.jar.location" value="${env.JAVA_HOME}${file.separator}tools${file.separator}ant-javafx.jar"/>
+    </target>
+    <target name="-pre-check-ant-javafx-version" depends="-set-ant-javafx-in-envjdk-tools" unless="ant-javafx-version-already-checked-in-jfximpl">
+        <condition property="do.check.ant-javafx.version">
+            <and>
+                <isset property="ant-javafx.jar.location"/>
+                <not><isset property="ant-javafx-version-already-checked-in-jfximpl"/></not>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-endorsed-javafx-ant-classpath" depends="-check-endorsed-javafx-ant-classpath,-pre-check-ant-javafx-version" if="endorsed-javafx-ant-classpath-available">
+        <property name="javafx.ant.classpath" value="${endorsed.javafx.ant.classpath}:${ant-javafx.jar.location}"/>
+    </target>
+    <target name="-set-javafx-ant-classpath" depends="-check-endorsed-javafx-ant-classpath,-pre-check-ant-javafx-version" unless="endorsed-javafx-ant-classpath-available">
+        <property name="javafx.ant.classpath" value="${ant-javafx.jar.location}"/>
+    </target>
+    <target name="-check-ant-javafx-version" depends="-pre-check-ant-javafx-version,
+            -set-endorsed-javafx-ant-classpath,-set-javafx-ant-classpath" if="do.check.ant-javafx.version">
+        <echo message="ant-javafx.jar.location = ${ant-javafx.jar.location}" level="verbose"/>
+        <echo message="javafx.ant.classpath = ${javafx.ant.classpath}" level="verbose"/>
+        <taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
+            uri="javafx:com.sun.javafx.tools.ant"
+            classpath="${javafx.ant.classpath}"/>
+        <condition property="have-fx-ant-init">
+            <typefound name="javafx:com.sun.javafx.tools.ant:init-ant"/>
+        </condition>
+        <property name="ant-javafx-version-already-checked-in-jfximpl" value="true"/>
+        <echo message="have-fx-ant-init = ${have-fx-ant-init}" level="verbose"/>
+    </target>
+    <target name="-check-jfx-sdk-version-old" depends="-check-ant-javafx-version" unless="have-fx-ant-init">
+        <property name="javafx.ant.version" value="1.0"/>
+    </target>
+    <target name="-check-jfx-sdk-version-new" depends="-check-ant-javafx-version" if="have-fx-ant-init">
+        <fx:init-ant/>
+        <condition property="have-fx-ant-api-1.1">
+            <!-- new features from JavaFX 2.0.2 are available in API version 1.1 or later -->
+            <matches pattern="1.[1-9]" string="${javafx.ant.version}"/>
+        </condition>
+        <condition property="have-fx-ant-api-1.2">
+            <!-- new features from JavaFX 2.2 are available in API version 1.2 or later -->
+            <matches pattern="1.[2-9]" string="${javafx.ant.version}"/>
+        </condition>
+    </target>
+    <target name="-check-jfx-sdk-version" depends="-check-jfx-sdk-version-old, -check-jfx-sdk-version-new" unless="jfx.sdk.version.checked">
+        <echo message="Detected JavaFX Ant API version ${javafx.ant.version}" level="info"/>
+        <echo message="have-fx-ant-api-1.1 = ${have-fx-ant-api-1.1}" level="verbose"/>
+        <echo message="have-fx-ant-api-1.2 = ${have-fx-ant-api-1.2}" level="verbose"/>
+        <echo message="javafx.ant.classpath = ${javafx.ant.classpath}" level="verbose"/>
+        <property name="jfx.sdk.version.checked" value="true"/>
+    </target>
+
+    <target name="-check-jfx-deployment" depends="-check-jdk-version,-check-jfx-sdk-version">
+        <condition property="jfx-deployment-available">
+            <and>
+                <or>
+                    <isset property="do.set.ant-javafx.in.fxsdk.lib"/>
+                    <isset property="do.set.ant-javafx.in.fxsdk.tools"/>
+                    <isset property="do.set.ant-javafx.in.platform.home.lib"/>
+                    <isset property="do.set.ant-javafx.in.platform.home.tools"/>
+                    <isset property="do.set.ant-javafx.in.probjdk.lib"/>
+                    <isset property="do.set.ant-javafx.in.probjdk.tools"/>
+                    <isset property="do.set.ant-javafx.in.envjdk.lib"/>
+                    <isset property="do.set.ant-javafx.in.envjdk.tools"/>
+                </or>
+                <isset property="ant-javafx.jar.location"/>
+            </and>
+        </condition>
+        <condition property="jfx-deployment-missing+jdk7u6">
+            <and>
+                <not><isset property="jfx-deployment-available"/></not>
+                <not><isset property="have-jdk-pre7u6"/></not>
+            </and>
+        </condition>
+        <condition property="jfx-deployment-missing+javafx.sdk.missing+default">
+            <and>
+                <not><isset property="jfx-deployment-available"/></not>
+                <isset property="have-jdk-pre7u6"/>
+                <isset property="javafx.sdk.missing+default"/>
+            </and>
+        </condition>
+        <condition property="jfx-deployment-missing+javafx.sdk.missing-default">
+            <and>
+                <not><isset property="jfx-deployment-available"/></not>
+                <isset property="have-jdk-pre7u6"/>
+                <isset property="javafx.sdk.missing-default"/>
+            </and>
+        </condition>
+        <fail message="Error:${line.separator}JavaFX deployment library not found in active JDK.${line.separator}Please check that the JDK is correctly installed and its version is at least 7u4 on Mac or 7u6 on other systems." if="jfx-deployment-missing+jdk7u6"/>
+        <fail message="Error:${line.separator}JavaFX deployment library not found.${line.separator}JavaFX SDK path undefined. Check the definition of ${platform.active} in Java Platform Manager${line.separator}(or directly the properties platform.active and javafx.sdk in project.properties file).${line.separator}Note: If missing, the default JavaFX-enabled platform gets created automatically when creating a new JavaFX Project." if="jfx-deployment-missing+javafx.sdk.missing+default"/>
+        <fail message="Error:${line.separator}JavaFX deployment library not found.${line.separator}JavaFX SDK path undefined. Check the definition of ${platform.active} in Java Platform Manager${line.separator}(or directly the properties platform.active and javafx.sdk in project.properties file)." if="jfx-deployment-missing+javafx.sdk.missing-default"/>
+        <fail message="Error:${line.separator}JavaFX deployment library not found." unless="jfx-deployment-available"/>
+        <echo message="jfx-deployment-available = ${jfx-deployment-available}" level="verbose"/>
+    </target>
+    
+    
+    <!-- Check availability of main JavaFX runtime jar (jfxrt.jar) -->
+
+    <target name="-check-property-javafx.runtime">
+        <echo message="javafx.runtime = ${javafx.runtime}" level="verbose"/>
+        <condition property="javafx.runtime.defined">
+            <and>
+                <isset property="javafx.runtime"/>
+                <not><contains string="${javafx.runtime}" substring="$${platform" casesensitive="false"/></not>
+            </and>
+        </condition>
+        <condition property="javafx.runtime.missing+default">
+            <and>
+                <equals arg1="${platform.active}" arg2="Default_JavaFX_Platform" trim="true"/>
+                <not><isset property="javafx.runtime.defined"/></not>
+            </and>
+        </condition>
+        <condition property="javafx.runtime.missing-default">
+            <and>
+                <not><equals arg1="${platform.active}" arg2="Default_JavaFX_Platform" trim="true"/></not>
+                <not><isset property="javafx.runtime.defined"/></not>
+            </and>
+        </condition>
+        <echo message="javafx.runtime.defined = ${javafx.runtime.defined}" level="verbose"/>
+        <echo message="javafx.runtime.missing+default = ${javafx.runtime.missing+default}" level="verbose"/>
+        <echo message="javafx.runtime.missing-default = ${javafx.runtime.missing-default}" level="verbose"/>
+    </target>
+
+    <target name="-check-jfxrt-in-fxrt" depends="-check-property-javafx.runtime" if="javafx.runtime.defined">
+        <condition property="do.set.jfxrt.in.fxrt">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${javafx.runtime}${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-fxrt" depends="-check-jfxrt-in-fxrt" if="do.set.jfxrt.in.fxrt">
+        <property name="jfxrt.jar.location" value="${javafx.runtime}${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-fxsdk-jre" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.jfxrt.in.fxsdk.jre">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${javafx.sdk}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-fxsdk-jre" depends="-set-jfxrt-in-fxrt,-check-jfxrt-in-fxsdk-jre" if="do.set.jfxrt.in.fxsdk.jre">
+        <property name="jfxrt.jar.location" value="${javafx.sdk}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-fxsdk-rt" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.jfxrt.in.fxsdk.rt">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${javafx.sdk}${file.separator}rt${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-fxsdk-rt" depends="-set-jfxrt-in-fxsdk-jre,-check-jfxrt-in-fxsdk-rt" if="do.set.jfxrt.in.fxsdk.rt">
+        <property name="jfxrt.jar.location" value="${javafx.sdk}${file.separator}rt${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-platform-home-jre" if="platform.home">
+        <condition property="do.set.jfxrt.in.platform.home.jre">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${platform.home}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-platform-home-jre" depends="-set-jfxrt-in-fxsdk-rt,-check-jfxrt-in-platform-home-jre" if="do.set.jfxrt.in.platform.home.jre">
+        <property name="jfxrt.jar.location" value="${platform.home}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-platform-home-rt" if="platform.home">
+        <condition property="do.set.jfxrt.in.platform.home.rt">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${platform.home}${file.separator}rt${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-platform-home-rt" depends="-set-jfxrt-in-platform-home-jre,-check-jfxrt-in-platform-home-rt" if="do.set.jfxrt.in.platform.home.rt">
+        <property name="jfxrt.jar.location" value="${platform.home}${file.separator}rt${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-jre" unless="jfxrt.jar.location">
+        <condition property="do.set.jfxrt.in.jre">
+            <and>
+                <not><isset property="jfxrt.jar.location"/></not>
+                <available file="${java.home}${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-jre" depends="-set-jfxrt-in-platform-home-rt,-check-jfxrt-in-jre" if="do.set.jfxrt.in.jre">
+        <property name="jfxrt.jar.location" value="${java.home}${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-check-jfxrt-in-envjdk-jre" unless="jfxrt.jar.location">
+        <property environment="env"/>
+        <condition property="do.set.jfxrt.in.envjdk.jre">
+            <and>
+                <not><isset property="ant-javafx.jar.location"/></not>
+                <available file="${env.JAVA_HOME}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-jfxrt-in-envjdk-jre" depends="-set-jfxrt-in-jre,-check-jfxrt-in-envjdk-jre" if="do.set.jfxrt.in.envjdk.jre">
+        <property name="jfxrt.jar.location" value="${env.JAVA_HOME}${file.separator}jre${file.separator}lib${file.separator}jfxrt.jar"/>
+    </target>
+    <target name="-pre-check-jfx-runtime" depends="-set-jfxrt-in-envjdk-jre">
+        <echo message="jfxrt.jar.location = ${jfxrt.jar.location}" level="verbose"/>
+    </target>
+
+    <target name="-check-jfx-runtime" depends="-check-jdk-version, -pre-check-jfx-runtime">
+        <condition property="jfx-runtime-available">
+            <and>
+                <or>
+                    <isset property="do.set.jfxrt.in.fxrt"/>
+                    <isset property="do.set.jfxrt.in.fxsdk.jre"/>
+                    <isset property="do.set.jfxrt.in.fxsdk.rt"/>
+                    <isset property="do.set.jfxrt.in.platform.home.jre"/>
+                    <isset property="do.set.jfxrt.in.platform.home.rt"/>
+                    <isset property="do.set.jfxrt.in.jre"/>
+                    <isset property="do.set.jfxrt.in.envjdk.jre"/>
+                </or>
+                <isset property="jfxrt.jar.location"/>
+            </and>
+        </condition>
+        <fail message="Error:${line.separator}JavaFX runtime JAR not found." unless="jfx-runtime-available"/>
+        <echo message="jfx-runtime-available = ${jfx-runtime-available}" level="verbose"/>
+    </target>
+
+
+    <!-- Check availability of WebStart executable -->
+
+    <target name="-check-webstart-in-fxrt" depends="-check-property-javafx.runtime" if="javafx.runtime.defined">
+        <condition property="do.set.webstart.in.fxrt">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <isset property="javafx.runtime.defined"/>
+                <or>
+                    <available file="${javafx.runtime}${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${javafx.runtime}${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-fxrt" depends="-check-webstart-in-fxrt" if="do.set.webstart.in.fxrt">
+        <property name="active.webstart.executable" value="${javafx.runtime}${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-fxsdk-jre" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.webstart.in.fxsdk.jre">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <isset property="javafx.sdk.defined"/>
+                <or>
+                    <available file="${javafx.sdk}${file.separator}jre${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${javafx.sdk}${file.separator}jre${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-fxsdk-jre" depends="-set-webstart-in-fxrt,-check-webstart-in-fxsdk-jre" if="do.set.webstart.in.fxsdk.jre">
+        <property name="active.webstart.executable" value="${javafx.sdk}${file.separator}jre${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-fxsdk" depends="-check-property-javafx.sdk" if="javafx.sdk.defined">
+        <condition property="do.set.webstart.in.fxsdk">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <isset property="javafx.sdk.defined"/>
+                <or>
+                    <available file="${javafx.sdk}${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${javafx.sdk}${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-fxsdk" depends="-set-webstart-in-fxsdk-jre,-check-webstart-in-fxsdk" if="do.set.webstart.in.fxsdk">
+        <property name="active.webstart.executable" value="${javafx.sdk}${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-platform-home-jre" if="platform.home">
+        <condition property="do.set.webstart.in.platform.home.jre">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <or>
+                    <available file="${platform.home}${file.separator}jre${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${platform.home}${file.separator}jre${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-platform-home-jre" depends="-set-webstart-in-fxsdk,-check-webstart-in-platform-home-jre" if="do.set.webstart.in.platform.home.jre">
+        <property name="active.webstart.executable" value="${platform.home}${file.separator}jre${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-platform-home" if="platform.home">
+        <condition property="do.set.webstart.in.platform.home">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <or>
+                    <available file="${platform.home}${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${platform.home}${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-platform-home" depends="-set-webstart-in-platform-home-jre,-check-webstart-in-platform-home" if="do.set.webstart.in.platform.home">
+        <property name="active.webstart.executable" value="${platform.home}${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-jre" unless="active.webstart.executable">
+        <condition property="do.set.webstart.in.jre">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <or>
+                    <available file="${java.home}${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${java.home}${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-jre" depends="-set-webstart-in-platform-home,-check-webstart-in-jre" if="do.set.webstart.in.jre">
+        <property name="active.webstart.executable" value="${java.home}${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-probjdk" unless="active.webstart.executable">
+        <condition property="do.set.webstart.in.probjdk">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <or>
+                    <available file="${java.home}${file.separator}..${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${java.home}${file.separator}..${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-probjdk" depends="-set-webstart-in-jre,-check-webstart-in-probjdk" if="do.set.webstart.in.probjdk">
+        <property name="active.webstart.executable" value="${java.home}${file.separator}..${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-check-webstart-in-envjdk" unless="active.webstart.executable">
+        <property environment="env"/>
+        <condition property="do.set.webstart.in.envjdk">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <or>
+                    <available file="${env.JAVA_HOME}${file.separator}bin${file.separator}javaws.exe"/>
+                    <available file="${env.JAVA_HOME}${file.separator}bin${file.separator}javaws"/>
+                </or>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-webstart-in-envjdk" depends="-set-webstart-in-probjdk,-check-webstart-in-envjdk" if="do.set.webstart.in.envjdk">
+        <property name="active.webstart.executable" value="${env.JAVA_HOME}${file.separator}bin${file.separator}javaws"/>
+    </target>
+    <target name="-pre-check-webstart-in-unix" depends="-check-operating-system,-set-webstart-in-envjdk" unless="active.webstart.executable">
+        <condition property="running.on.unix-active.webstart.executable">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <isset property="running.on.unix"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-check-webstart-in-unix" depends="-pre-check-webstart-in-unix" if="running.on.unix-active.webstart.executable">
+        <local name="exec.which.javaws.result"/>
+        <exec executable="which" failifexecutionfails="false" failonerror="false" resultproperty="exec.which.javaws.result" outputproperty="exec.which.javaws.output">
+            <arg value="javaws"/>
+        </exec>
+        <condition property="do.set.webstart.in.unix">
+            <and>
+                <not><isset property="active.webstart.executable"/></not>
+                <isset property="exec.which.javaws.result"/>
+                <equals arg1="${exec.which.javaws.result}" arg2="0"/>
+                <isset property="exec.which.javaws.output"/>
+                <not><equals arg1="${exec.which.javaws.output}" arg2=""/></not>
+            </and>
+        </condition>
+        <echo message="do.set.webstart.in.unix = ${do.set.webstart.in.unix}" level="verbose"/>
+    </target>
+    <target name="-set-webstart-in-unix" depends="-set-webstart-in-envjdk,-check-webstart-in-unix" if="do.set.webstart.in.unix">
+        <property name="active.webstart.executable" value="${exec.which.javaws.output}"/>
+    </target>
+    <target name="-pre-check-jfx-webstart" depends="-set-webstart-in-unix">
+        <echo message="active.webstart.executable = ${active.webstart.executable}" level="verbose"/>
+    </target>
+
+    <target name="-check-jfx-webstart" depends="-pre-check-jfx-webstart">
+        <condition property="jfx-webstart-available">
+            <and>
+                <or>
+                    <isset property="do.set.webstart.in.fxrt"/>
+                    <isset property="do.set.webstart.in.fxsdk.jre"/>
+                    <isset property="do.set.webstart.in.fxsdk"/>
+                    <isset property="do.set.webstart.in.platform.home.jre"/>
+                    <isset property="do.set.webstart.in.platform.home"/>
+                    <isset property="do.set.webstart.in.jre"/>
+                    <isset property="do.set.webstart.in.probjdk"/>
+                    <isset property="do.set.webstart.in.envjdk"/>
+                    <isset property="do.set.webstart.in.unix"/>
+                </or>
+                <isset property="active.webstart.executable"/>
+            </and>
+        </condition>
+        <condition property="jfx-webstart-missing+jdk7u6">
+            <and>
+                <not><isset property="jfx-webstart-available"/></not>
+                <not><isset property="have-jdk-pre7u6"/></not>
+            </and>
+        </condition>
+        <condition property="jfx-webstart-missing+javafx.runtime.missing+default">
+            <and>
+                <not><isset property="jfx-webstart-available"/></not>
+                <isset property="have-jdk-pre7u6"/>
+                <isset property="javafx.runtime.missing+default"/>
+            </and>
+        </condition>
+        <condition property="jfx-webstart-missing+javafx.runtime.missing-default">
+            <and>
+                <not><isset property="jfx-webstart-available"/></not>
+                <isset property="have-jdk-pre7u6"/>
+                <isset property="javafx.runtime.missing-default"/>
+            </and>
+        </condition>
+        <fail message="Error:${line.separator}WebStart executable could not be found in active JDK.${line.separator}Please check that the JDK is correctly installed and its version is at least 7u6." if="jfx-webstart-missing+jdk7u6"/>
+        <fail message="Error:${line.separator}WebStart executable could not be found.${line.separator}JavaFX RT path undefined. Check the definition of ${platform.active} in Java Platform Manager${line.separator}(or directly the properties platform.active and javafx.runtime in project.properties file).${line.separator}Note: If missing, the default JavaFX-enabled platform gets created automatically when creating a new JavaFX Project." if="jfx-webstart-missing+javafx.runtime.missing+default"/>
+        <fail message="Error:${line.separator}WebStart executable could not be found.${line.separator}JavaFX RT path undefined. Check the definition of ${platform.active} in Java Platform Manager${line.separator}(or directly the properties platform.active and javafx.runtime in project.properties file)." if="jfx-webstart-missing+javafx.runtime.missing-default"/>
+        <fail message="Error:${line.separator}WebStart executable could not be found." unless="jfx-webstart-available"/>
+        <echo message="jfx-webstart-available = ${jfx-webstart-available}" level="verbose"/>
+    </target>
+
+    
+    <!-- Legacy targets kept for compatibility with older build-impl.xml scripts -->
+
+    <!-- Note: target "-check-javafx" is not necessary any more but is referenced from NB 7.1 build-impl.xml -->
+    <target name="-check-javafx"/>
+    <!-- Note: target "-javafx-check-error" is not necessary any more but is referenced from NB 7.1 build-impl.xml -->
+    <target name="-javafx-check-error"/>    
+    <!-- Note: target "-init-javafx" is not necessary any more but is referenced from NB 7.1 build-impl.xml -->
+    <target name="-init-javafx"/>
+
+    
+    <!-- Check project properties -->
+    
+    <target name="-check-default-run-config" unless="config">
+        <property name="config" value="&lt;default config&gt;"/>
+    </target>
+    
+    <target name="-check-project">
+        <condition property="main-class-available">
+            <isset property="javafx.main.class"/>
+        </condition>
+        <condition property="vmargs-available">
+            <and>
+                <isset property="run.jvmargs"/>
+                <not><equals arg1="${run.jvmargs}" arg2=""/></not>
+            </and>
+        </condition>
+        <condition property="preloader-available">
+            <and>
+                <isset property="javafx.preloader.enabled"/>
+                <equals arg1="${javafx.preloader.enabled}" arg2="true"/>
+                <isset property="javafx.preloader.class"/>
+                <not><equals arg1="${javafx.preloader.class}" arg2=""/></not>
+                <isset property="javafx.preloader.jar.filename"/>
+                <not><equals arg1="${javafx.preloader.jar.filename}" arg2=""/></not>
+            </and>
+        </condition>
+        <condition property="app-with-preloader">
+            <and>
+                <istrue value="${preloader-available}"/>
+                <istrue value="${main-class-available}"/>
+            </and>
+        </condition>
+        <condition property="app-with-external-preloader-jar">
+            <and>
+                <isset property="app-with-preloader"/>
+                <isset property="javafx.preloader.type"/>
+                <equals arg1="${javafx.preloader.type}" arg2="jar" trim="true"/>
+            </and>
+        </condition>
+        <condition property="app-without-preloader">
+            <and>
+                <not>
+                    <istrue value="${preloader-available}"/>
+                </not>
+                <istrue value="${main-class-available}"/>
+            </and>
+        </condition>
+        <condition property="preloader-app">
+            <and>
+                <isset property="javafx.preloader"/>
+                <equals arg1="${javafx.preloader}" arg2="true"/>
+            </and>
+        </condition>
+        <condition property="fx-in-swing-app">
+            <and>
+                <isset property="javafx.swing"/>
+                <equals arg1="${javafx.swing}" arg2="true"/>
+            </and>
+        </condition>
+        <condition property="fx-in-swing-workaround-app">
+            <and>
+                <istrue value="${fx-in-swing-app}"/>
+                <istrue value="${preloader-app}"/>
+            </and>
+        </condition>
+        <condition property="preloader-app-no-workaround">
+            <and>
+                <istrue value="${preloader-app}"/>
+                <not><istrue value="${fx-in-swing-app}"/></not>
+            </and>
+        </condition>
+        <condition property="html-template-available">
+            <and>
+                <isset property="javafx.run.htmltemplate"/>
+                <not>
+                    <equals arg1="${javafx.run.htmltemplate}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <condition property="icon-available">
+            <and>
+                <isset property="javafx.deploy.icon"/>
+                <not>
+                    <equals arg1="${javafx.deploy.icon}" arg2=""/>
+                </not>
+            </and>
+        </condition>
+        <condition property="dimensions-available">
+            <and>
+                <isset property="javafx.run.width"/>
+                <isset property="javafx.run.height"/>
+                <not><equals arg1="${javafx.run.width}" arg2=""/></not>
+                <not><equals arg1="${javafx.run.height}" arg2=""/></not>
+            </and>
+        </condition>
+        <condition property="update-mode-background">
+            <and>
+                <isset property="javafx.deploy.backgroundupdate"/>
+                <equals arg1="${javafx.deploy.backgroundupdate}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <condition property="offline-allowed">
+            <and>
+                <isset property="javafx.deploy.allowoffline"/>
+                <equals arg1="${javafx.deploy.allowoffline}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <condition property="permissions-elevated">
+            <and>
+                <isset property="javafx.deploy.permissionselevated"/>
+                <equals arg1="${javafx.deploy.permissionselevated}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <condition property="binary-encode-css">
+            <and>
+                <isset property="javafx.binarycss"/>
+                <equals arg1="${javafx.binarycss}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <condition property="rebase-lib-jars">
+            <and>
+                <isset property="javafx.rebase.libs"/>
+                <equals arg1="${javafx.rebase.libs}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <echo message="main-class-available = ${main-class-available}" level="verbose"/>
+        <echo message="vmargs-available = ${vmargs-available}" level="verbose"/>
+        <echo message="preloader-available = ${preloader-available}" level="verbose"/>
+        <echo message="app-with-preloader = ${app-with-preloader}" level="verbose"/>
+        <echo message="app-with-preloader-without-project = ${app-with-preloader-without-project}" level="verbose"/>
+        <echo message="app-without-preloader = ${app-without-preloader}" level="verbose"/>
+        <echo message="preloader-app = ${preloader-app}" level="verbose"/>
+        <echo message="fx-in-swing-app = ${fx-in-swing-app}" level="verbose"/>
+        <echo message="fx-in-swing-workaround-app = ${fx-in-swing-workaround-app}" level="verbose"/>
+        <echo message="preloader-app-no-workaround = ${preloader-app-no-workaround}" level="verbose"/>
+        <echo message="html-template-available = ${html-template-available}" level="verbose"/>
+        <echo message="icon-available = ${icon-available}" level="verbose"/>
+        <echo message="dimensions-available = ${dimensions-available}" level="verbose"/>
+        <echo message="update-mode-background = ${update-mode-background}" level="verbose"/>
+        <echo message="offline-allowed = ${offline-allowed}" level="verbose"/>
+        <echo message="permissions-elevated = ${permissions-elevated}" level="verbose"/>
+        <echo message="binary-encode-css = ${binary-encode-css}" level="verbose"/>
+        <echo message="rebase-lib-jars = ${rebase-lib-jars}" level="verbose"/>
+    </target>
+
+    <target name="-swing-api-check" depends="-check-project,-check-jfx-deployment" if="fx-in-swing-app">
+        <condition property="fx-in-swing-app-workaround">
+            <and>
+                <isset property="fx-in-swing-app"/>
+                <not><isset property="have-fx-ant-api-1.2"/></not>
+            </and>
+        </condition>
+    </target>
+    <target name="-swing-api-warning" depends="-swing-api-check" if="fx-in-swing-app-workaround">
+        <echo message="Info: No support for FX-in-Swing deployment detected in current JavaFX SDK. Using workaround instead."/>
+    </target>
+
+    <target name="-icon-deployment-check" depends="-check-project,-check-jfx-deployment" if="icon-available">
+        <condition property="icon-deployment-may-not-be-supported">
+            <and>
+                <isset property="icon-available"/>
+                <not><isset property="have-fx-ant-api-1.1"/></not>
+            </and>
+        </condition>
+    </target>
+    <target name="-icon-warning" depends="-icon-deployment-check" if="icon-deployment-may-not-be-supported">
+        <echo message="Warning: Note that due to a bug in early JavaFX 2.0 SDK distributions the icon may not be properly set in deployment files."/>
+    </target>
+
+    <target name="-set-dimensions" depends="-check-project" if="dimensions-available">
+        <property name="javafx.width" value="${javafx.run.width}"/>
+        <property name="javafx.height" value="${javafx.run.height}"/>
+    </target>
+    <target name="-reset-dimensions" depends="-check-project" unless="dimensions-available">
+        <property name="javafx.width" value="800"/>
+        <property name="javafx.height" value="600"/>
+    </target>
+
+    <target name="-set-update-mode-background" depends="-check-project" if="update-mode-background">
+        <property name="update-mode" value="background"/>
+    </target>
+    <target name="-set-update-mode-eager" depends="-check-project" unless="update-mode-background">
+        <property name="update-mode" value="eager"/>
+    </target>
+
+    <target name="-set-permissions-elevated" depends="-check-project" if="permissions-elevated">
+        <property name="permissions.elevated" value="true"/>
+    </target>
+    <target name="-reset-permissions-elevated" depends="-check-project" unless="permissions-elevated">
+        <property name="permissions.elevated" value="false"/>
+    </target>
+
+    <target name="-set-binary-css" depends="-check-project,-init-css-conversion" if="do.copy.binary.css">
+        <property name="css-include-ext" value="bss"/>
+        <property name="css-exclude-ext" value="css"/>
+    </target>
+    <target name="-unset-binary-css" depends="-check-project,-init-css-conversion" unless="do.copy.binary.css">
+        <property name="css-include-ext" value="css"/>
+        <property name="css-exclude-ext" value="bss"/>
+    </target>
+    <target name="-copy-binary-css" depends="-init-css-conversion,-set-binary-css,-unset-binary-css,-copy-binary-css-bypass,-copy-binary-css-impl"/>
+    <target name="-init-css-conversion" depends="-check-project,-check-jdk-version">
+        <fileset id="cssfiles" dir="${basedir}${file.separator}${build.classes.dir}">
+            <include name="**${file.separator}*.css"/>
+        </fileset>
+        <pathconvert refid="cssfiles" property="cssfileset.notempty" setonempty="false"/>
+        <condition property="do.copy.binary.css">
+            <and>
+                <isset property="binary-encode-css"/>
+                <isset property="cssfileset.notempty"/>
+                <not><isset property="have-jdk7-css2bin-bug"/></not>
+            </and>
+        </condition>
+        <condition property="do.bypass.binary.css">
+            <and>
+                <isset property="binary-encode-css"/>
+                <isset property="cssfileset.notempty"/>
+                <isset property="have-jdk7-css2bin-bug"/>
+            </and>
+        </condition>
+        <echo message="do.copy.binary.css = ${do.copy.binary.css}" level="verbose"/>
+        <echo message="do.bypass.binary.css = ${do.bypass.binary.css}" level="verbose"/>
+    </target>
+    <target name="-copy-binary-css-bypass" depends="-init-css-conversion" if="do.bypass.binary.css">
+        <echo message="Warning: Bypassing FX CSS to BSS conversion due to a bug in &lt;fx:csstobin&gt; task in current JDK platform" level="warning"/>
+    </target>
+    <target name="-copy-binary-css-impl" depends="-init-css-conversion" if="do.copy.binary.css">
+        <property name="cssfileslist" refid="cssfiles"/>
+        <echo message="css files to binary convert: " level="verbose">${cssfileslist}</echo>
+        <fx:csstobin outdir="${basedir}${file.separator}${build.classes.dir}">
+            <fileset refid="cssfiles"/>
+        </fx:csstobin>
+    </target>
+
+
+    <!-- Copy dependent libraries -->
+    
+    <!-- Note: target "-jfx-copylibs" is referenced from NB 7.1 build-impl.xml -->
+    <target name="-jfx-copylibs" depends="init,compile,-pre-pre-jar,-pre-jar,-jfx-copylibs-warning" unless="fallback.no.javascript">
+        <jfx-copylibs-js-impl/>
+    </target>
+    <target name="-jfx-copylibs-warning" if="fallback.no.javascript">
+        <echo message="Warning: Dependent Libraries copy (-jfx-copylibs) skipped in fallback build mode due to JDK missing JavaScript support."/>
+    </target>
+    <macrodef name="jfx-copylibs-js-impl">
+        <sequential>
+            <local name="run.classpath.without.build.classes.and.dist.dir"/>
+            <pathconvert property="run.classpath.without.build.classes.and.dist.dir">
+                <path path="${run.classpath}"/>
+                <map from="${basedir}${file.separator}${build.classes.dir}" to=""/>
+                <map from="${basedir}${file.separator}${dist.jar}" to=""/>
+                <map from="${javafx.runtime}${file.separator}lib${file.separator}jfxrt.jar" to=""/>
+                <map from="${javafx.runtime}${file.separator}lib${file.separator}deploy.jar" to=""/>
+                <map from="${javafx.runtime}${file.separator}lib${file.separator}javaws.jar" to=""/>
+                <map from="${javafx.runtime}${file.separator}lib${file.separator}plugin.jar" to=""/>
+            </pathconvert>
+            <!-- add possibly missing dependencies at distance 2 (build system logic thus provides transitive closure) -->
+            <local name="run.and.lib.classpath"/>
+            <echo message="JavaScript: -jfx-copylibs" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var pathConvert = project.createTask("pathconvert");
+                    pathConvert.setProperty("run.and.lib.classpath");
+                    var classPath = project.getProperty("run.classpath.without.build.classes.and.dist.dir");
+                    var fileSeparator = project.getProperty("file.separator");
+                    if(classPath != null) {
+                        var classPathCopy = pathConvert.createPath();
+                        classPathCopy.setPath(classPath);
+                        if(classPath.indexOf(";") != -1) {
+                            var pathArray = classPath.split(";");
+                        } else {
+                            var pathArray = classPath.split(":");
+                        }
+                        var added = "";
+                        for (var i=0; i<pathArray.length; i++) {
+                            var index = pathArray[i].lastIndexOf(fileSeparator);
+                            if (index >=0) {
+                                var onePath = pathArray[i].substr(0,index+1) + "lib";
+                                var oneDir = new java.io.File(onePath);
+                                if(oneDir.exists()) {
+                                    var fs = project.createDataType("fileset");
+                                    fs.setDir( oneDir );
+                                    fs.setIncludes("*.jar");
+                                    var ds = fs.getDirectoryScanner(project);
+                                    var srcFiles = ds.getIncludedFiles();
+                                    for (j=0; j<srcFiles.length; j++) {
+                                        if(classPath.indexOf(srcFiles[j]) == -1 && added.indexOf(srcFiles[j]) == -1) {
+                                            var path = pathConvert.createPath();
+                                            path.setPath(onePath + fileSeparator + srcFiles[j]);
+                                            added += srcFiles[j];
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    pathConvert.perform();
+                ]]>
+            </script>
+            <echo message="run.and.lib.classpath = ${run.and.lib.classpath}" level="verbose"/>
+            <delete dir="${dist.dir}${file.separator}lib" includeEmptyDirs="true" quiet="true"/>
+            <copy todir="${dist.dir}${file.separator}lib" flatten="true" preservelastmodified="true" overwrite="true">
+                <path>
+                    <pathelement path="${run.and.lib.classpath}"/>
+                </path>
+            </copy>
+        </sequential>
+    </macrodef>
+    
+    <target name="-copy-external-preloader-jar" depends="-check-project" if="app-with-external-preloader-jar">
+        <copy file="${javafx.preloader.jar.path}" todir="${dist.dir}${file.separator}lib"/>
+    </target>
+
+
+    <!-- Optional classpath re-base of dependent JAR manifests after copy to lib/, required by GlassFish -->
+
+    <!-- Note: target "-rebase-libs" is referenced from NB 7.1 build-impl.xml -->
+    <target name="-rebase-libs" depends="-check-project, -jfx-copylibs, -check-rebase-libs, -rebase-libs-warning" if="do-rebase-lib-jars">
+        <rebase-libs-js-impl/>
+    </target>
+    <target name="-check-rebase-libs">
+        <condition property="do-rebase-lib-jars">
+            <and>
+                <isset property="rebase-lib-jars"/>
+                <not><isset property="fallback.no.javascript"/></not>
+            </and>
+        </condition>
+        <condition property="do-skip-rebase-libs">
+            <and>
+                <isset property="rebase-lib-jars"/>
+                <isset property="fallback.no.javascript"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-rebase-libs-warning" depends="-check-rebase-libs" if="do-skip-rebase-libs">
+        <echo message="Warning: Dependent Libraries JARs rebase (-rebase-libs) skipped in fallback build mode due to JDK missing JavaScript support."/>
+    </target>
+
+    <macrodef name="rebase-libs-js-impl">
+        <sequential>
+            <property name="pp_rebase_dir" value="${basedir}${file.separator}${dist.dir}${file.separator}lib"/>
+            <property name="pp_rebase_fs" value="*.jar"/>
+            <echo message="JavaScript: -rebase-libs-js-impl" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var dir = project.getProperty("pp_rebase_dir");
+                    var fDir = new java.io.File(dir);
+                    if( fDir.exists() ) {
+                        var callTask = project.createTask("antcall");
+                        callTask.setTarget("-rebase-libs-macro-call");
+                        var param = callTask.createParam();
+                        param.setName("jar.file.to.rebase");
+                        var includes = project.getProperty("pp_rebase_fs");
+                        var fs = project.createDataType("fileset");
+                        fs.setDir( fDir );
+                        fs.setIncludes(includes);
+                        var ds = fs.getDirectoryScanner(project);
+                        var srcFiles = ds.getIncludedFiles();
+                        for (i=0; i<srcFiles.length; i++) {
+                            param.setValue(dir + "${file.separator}" + srcFiles[i]);
+                            callTask.perform();
+                        }
+                    }
+                ]]>
+            </script>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="rebase-lib">
+        <attribute name="jarfile"/>
+        <sequential>
+            <local name="tmpdir"/>
+            <property name="tmpdir" value="${java.io.tmpdir}${file.separator}${user.name}_${ant.project.name}_rebase" />
+            <echo message="tmpdir = ${tmpdir}" level="verbose"/>
+            <delete dir="${tmpdir}" quiet="true"/>
+            <mkdir dir="${tmpdir}"/>
+            <unzip src="@{jarfile}" dest="${tmpdir}">
+                <patternset>
+                    <include name="META-INF${file.separator}MANIFEST.MF"/>
+                </patternset>
+            </unzip>
+            <local name="manifest.file.temp"/>
+            <property name="manifest.file.temp" value="${tmpdir}${file.separator}META-INF${file.separator}MANIFEST.MF" />
+            <echo message="manifest.file.temp = ${manifest.file.temp}" level="verbose"/>
+            <!-- edited manifest file -->
+            <local name="manifest.file.temp.new"/>
+            <property name="manifest.file.temp.new" value="${manifest.file.temp}_new" />
+            <echo message="manifest.file.temp.new = ${manifest.file.temp.new}" level="verbose"/>
+            <echo message="JavaScript: rebase-lib" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var UTF_8 = "UTF-8";
+                    var ATTR_CLASS_PATH = "Class-Path";
+                    var ATTR_CLASS_PATH_FX = "JavaFX-Class-Path";
+                    function isSigned(manifest) {        
+                        var sections = manifest.getSectionNames();
+                        while(sections.hasMoreElements()) {
+                            var sectionname = sections.nextElement();
+                            var section = manifest.getSection(sectionname);
+                            if(section != null) {
+                                var sectionKeys = section.getAttributeKeys();
+                                while (sectionKeys.hasMoreElements()) {
+                                    var element = sectionKeys.nextElement();
+                                    if (element.endsWith("-Digest") || element.endsWith("-digest")) {
+                                        return true;
+                                    }
+                                }
+                            }
+                        }
+                        return false;
+                    }
+                    var src = project.getProperty("manifest.file.temp");
+                    var srf = new java.io.File(src);
+                    try {
+                        var fis = new java.io.FileInputStream(srf);
+                        try {
+                            var isr = new java.io.InputStreamReader(fis, UTF_8);
+                            try {
+                                var manifest = new org.apache.tools.ant.taskdefs.Manifest(isr);
+                            } finally {
+                                isr.close();
+                            }
+                        } finally {
+                            fis.close();
+                        }
+                    } catch(e) {
+                        var manifest = null;
+                    }
+                    if(manifest != null) {
+                        if(isSigned(manifest)) {
+                            println("Warning: Signed JAR can not be rebased.");
+                        } else {
+                            var mainSection = manifest.getMainSection();
+                            var classPath = mainSection.getAttributeValue(ATTR_CLASS_PATH);
+                            if (classPath != null) {
+                                var classPathAttr = ATTR_CLASS_PATH;
+                            } else {
+                                classPath = mainSection.getAttributeValue(ATTR_CLASS_PATH_FX);
+                                if(classPath != null) {
+                                    var classPathAttr = ATTR_CLASS_PATH_FX;
+                                }
+                            }
+                            if(classPath != null) {
+                                var result = new java.lang.StringBuilder();
+                                var changed = false;
+                                var pathArray = classPath.split(" ");
+                                for (var i=0; i<pathArray.length; i++) {
+                                    if (result.length() > 0) {
+                                        result.append(' ');
+                                    }
+                                    var index = pathArray[i].lastIndexOf('/');
+                                    if (index >=0 && index < pathArray[i].length()-1) {
+                                        pathArray[i] = pathArray[i].substring(index+1);
+                                        changed = true;
+                                    }
+                                    result.append(pathArray[i]);
+                                }
+                                mainSection.removeAttribute(classPathAttr);
+                                mainSection.addAttributeAndCheck(new org.apache.tools.ant.taskdefs.Manifest.Attribute(classPathAttr, result.toString()));
+                                var tgt = project.getProperty("manifest.file.temp.new");
+                                var tgf = new java.io.File(tgt);
+                                try {
+                                    var fos = new java.io.FileOutputStream(tgf);
+                                    try {
+                                        var osw = new java.io.OutputStreamWriter(fos, UTF_8);
+                                        try {
+                                            var manifestOut = new java.io.PrintWriter(osw);
+                                            manifest.write(manifestOut);
+                                            manifestOut.close();
+                                        } finally {
+                                            osw.close();
+                                        }
+                                    } finally {
+                                        fos.close();
+                                    }
+                                } catch(e) {
+                                    println("Warning: problem storing rebased manifest file.");
+                                }
+                            }
+                        }
+                    }
+                ]]>
+            </script>
+            <antcall target="-move-new-manifest-if-exists">
+                <param name="move.file.from" value="${manifest.file.temp.new}"/>
+                <param name="move.file.to" value="${manifest.file.temp}"/>
+            </antcall>
+            <zip destfile="@{jarfile}" basedir="${tmpdir}" update="true"/>
+            <delete dir="${tmpdir}" quiet="true"/>
+        </sequential>
+    </macrodef>
+    
+    <target name="-new-temp-mainfest-existence">
+        <condition property="new-temp-manifest-exists">
+            <available file="${move.file.from}"/>
+        </condition>
+        <echo message="new-temp-manifest-exists = ${new-temp-manifest-exists}" level="verbose"/>
+    </target>
+    
+    <target name="-move-new-manifest-if-exists" depends="-new-temp-mainfest-existence" if="new-temp-manifest-exists">
+        <move file="${move.file.from}" tofile="${move.file.to}" failonerror="false"/>
+    </target>
+    
+    <target name="-rebase-libs-macro-call">
+        <echo message="Rebase jarfile = ${jar.file.to.rebase}" level="verbose"/>
+        <rebase-lib jarfile="${jar.file.to.rebase}"/>
+    </target>
+    
+
+    <!-- Main Deployment Target -->
+
+    <!-- Note: target "jfx-deployment" is referenced from NB 7.1+ build-impl.xml -->
+    <target name="jfx-deployment" depends="-check-jfx-deployment-launch,-do-jfx-deployment-script,-do-jfx-deployment-noscript" if="jfx-deployment-available"/>
+
+    <target name="-check-dist-lib-exists">
+        <deploy-defines/>
+        <available file="${jfx.deployment.dir}${file.separator}lib" type="dir" property="dist.lib.exists"/>
+    </target>
+    <target name="-check-jfx-deployment-jar-current-nolib" depends="-check-dist-lib-exists" unless="dist.lib.exists">
+        <uptodate property="jfx-deployment-jar-current" targetfile="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}" >
+            <srcfiles dir="${basedir}${file.separator}${build.classes.dir}" includes="**${file.separator}*"/>
+            <srcfiles dir="${basedir}${file.separator}nbproject" includes="**${file.separator}*"/>
+        </uptodate>
+    </target>
+    <target name="-check-jfx-deployment-jar-current-lib" depends="-check-dist-lib-exists" if="dist.lib.exists">
+        <uptodate property="jfx-deployment-jar-current" targetfile="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}" >
+            <srcfiles dir="${basedir}${file.separator}${build.classes.dir}" includes="**${file.separator}*"/>
+            <srcfiles dir="${jfx.deployment.dir}${file.separator}lib" includes="**${file.separator}*"/>
+            <srcfiles dir="${basedir}${file.separator}nbproject" includes="**${file.separator}*"/>
+        </uptodate>
+    </target>
+    <target name="-check-jfx-deployment-launch" depends="-check-jfx-deployment,-check-jfx-deployment-jar-current-nolib,-check-jfx-deployment-jar-current-lib">
+        <condition property="do-jfx-deployment-script">
+            <and>
+                <isset property="jfx-deployment-available"/>
+                <not><isset property="fallback.no.javascript"/></not>
+                <not><isset property="jfx-deployment-jar-current"/></not>
+            </and>
+        </condition>
+        <condition property="do-jfx-deployment-noscript">
+            <and>
+                <isset property="jfx-deployment-available"/>
+                <isset property="fallback.no.javascript"/>
+                <not><isset property="jfx-deployment-jar-current"/></not>
+            </and>
+        </condition>
+    </target>
+    <target name="-do-jfx-deployment-script" depends="-check-jfx-deployment-launch" if="do-jfx-deployment-script">
+        <antcall target="jfx-deployment-script"/>
+    </target>
+    <target name="-do-jfx-deployment-noscript" depends="-check-jfx-deployment-launch" if="do-jfx-deployment-noscript">
+        <antcall target="jfx-deployment-noscript"/>
+    </target>
+
+    <target name="jfx-deployment-script" depends="-check-jfx-deployment,-check-project,
+        -swing-api-warning,-icon-warning,
+        -set-dimensions,-reset-dimensions,-set-update-mode-background,-set-update-mode-eager,
+        -set-permissions-elevated,-reset-permissions-elevated,
+        -copy-external-preloader-jar,-copy-binary-css,
+        -deploy-app-sign-nopreloader-notemplate,
+        -deploy-app-sign-preloader-notemplate,
+        -deploy-app-sign-nopreloader-template,
+        -deploy-app-sign-preloader-template,
+        -deploy-app-sign-nopreloader-notemplate-swing,
+        -deploy-app-sign-nopreloader-template-swing,
+        -deploy-app-nosign-nopreloader-notemplate,
+        -deploy-app-nosign-preloader-notemplate,
+        -deploy-app-nosign-nopreloader-template,
+        -deploy-app-nosign-preloader-template,
+        -deploy-app-nosign-nopreloader-notemplate-swing,
+        -deploy-app-nosign-nopreloader-template-swing"
+        if="jfx-deployment-available">
+    </target>
+
+    <target name="jfx-deployment-noscript" depends="-check-jfx-deployment,-check-project,
+        -swing-api-warning,-icon-warning,
+        -set-dimensions,-reset-dimensions,-set-update-mode-background,-set-update-mode-eager,
+        -set-permissions-elevated,-reset-permissions-elevated,
+        -copy-external-preloader-jar,-copy-binary-css,
+        -fallback-deploy-app-sign-nopreloader-notemplate,
+        -fallback-deploy-app-sign-preloader-notemplate,
+        -fallback-deploy-app-sign-nopreloader-template,
+        -fallback-deploy-app-sign-preloader-template,
+        -fallback-deploy-app-sign-nopreloader-notemplate-swing,
+        -fallback-deploy-app-sign-nopreloader-template-swing,
+        -fallback-deploy-app-nosign-nopreloader-notemplate,
+        -fallback-deploy-app-nosign-preloader-notemplate,
+        -fallback-deploy-app-nosign-nopreloader-template,
+        -fallback-deploy-app-nosign-preloader-template,
+        -fallback-deploy-app-nosign-nopreloader-notemplate-swing,
+        -fallback-deploy-app-nosign-nopreloader-template-swing"
+        if="jfx-deployment-available">
+    </target>
+
+
+    <!-- Security / Signing -->
+    
+    <target name="-unavailable-signjars-task" depends="-check-jfx-deployment" unless="jfx-deployment-available">
+        <echo message="Warning: Task required to sign JAR file is missing, check the availability of JavaFX 2.0 deployment tasks. JAR files will not be signed."/>
+    </target>
+
+    <target name="-security-props-check">
+        <condition property="javafx.signed.true">
+            <istrue value="${javafx.signing.enabled}"/>
+        </condition>
+    </target>
+
+    <target name="-check-signing-possible" depends="-security-props-check,-check-jfx-deployment,-unavailable-signjars-task">
+        <condition property="javafx.signed.true+signjars.task.available">
+            <and>
+                <isset property="javafx.signed.true"/>
+                <isset property="jfx-deployment-available"/>
+            </and>
+        </condition>
+    </target>
+    
+    <target name="-javafx-init-keystore" depends="-check-signing-possible,-javafx-init-signing,-javafx-init-keystore1,-javafx-init-keystore2,-check-keystore-exists" 
+            if="javafx.signed.true+signjars.task.available" unless="javafx.signjar.keystore.exists">
+        <property name="javafx.signjar.vendor" value="CN=${application.vendor}"/>
+        <echo message="Going to create default keystore in ${javafx.signjar.keystore}"/>
+        <genkey dname="${javafx.signjar.vendor}" alias="${javafx.signjar.alias}" keystore="${javafx.signjar.keystore}"
+            storepass="${javafx.signjar.storepass}" keypass="${javafx.signjar.keypass}"/>
+    </target>
+    
+    <target name="-check-keystore-exists">
+        <available property="javafx.signjar.keystore.exists" file="${javafx.signjar.keystore}"/>
+    </target>
+
+    <target name="-javafx-init-signing">
+        <condition property="generated.key.signing">
+            <equals arg1="${javafx.signing.type}" arg2="self" trim="true"/>
+        </condition>
+    </target>
+
+    <target name="-javafx-init-keystore1" depends="-javafx-init-signing" if="generated.key.signing">
+        <property name="javafx.signjar.keystore" value="${basedir}${file.separator}build${file.separator}nb-jfx.jks" />
+        <property name="javafx.signjar.storepass" value="storepass"/>
+        <property name="javafx.signjar.keypass" value="keypass"/>
+        <property name="javafx.signjar.alias" value="nb-jfx"/>
+    </target>
+
+    <target name="-javafx-init-keystore2" depends="-javafx-init-signing" unless="generated.key.signing">
+        <property name="javafx.signjar.keystore" value="${javafx.signing.keystore}" />
+        <property name="javafx.signjar.storepass" value="${javafx.signing.keystore.password}"/>
+        <property name="javafx.signjar.keypass" value="${javafx.signing.keyalias.password}"/>
+        <property name="javafx.signjar.alias" value="${javafx.signing.keyalias}"/>
+    </target>
+
+    
+    <!-- Project Deployment Macros -->
+
+    <macrodef name="deploy-defines">
+        <sequential>
+            <basename property="jfx.deployment.jar" file="${dist.jar}"/>
+            <property name="jfx.deployment.dir" location="${dist.dir}"/>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="deploy-preprocess">
+        <sequential>
+            <delete includeEmptyDirs="true" quiet="true">
+                <fileset dir="${jfx.deployment.dir}${file.separator}lib">
+                    <exclude name="**${file.separator}*.jar"/>
+                </fileset>
+            </delete>
+        </sequential>
+    </macrodef>
+
+    <!-- fx:jar scripted call enables passing of arbitrarily long list of params and fx-version dependent behavior -->
+    <macrodef name="deploy-jar">
+        <sequential>
+            <antcall target="-pre-jfx-jar"/>
+            <echo message="javafx.ant.classpath = ${javafx.ant.classpath}" level="verbose"/>
+            <typedef name="fx_jar" classname="com.sun.javafx.tools.ant.FXJar" classpath="${javafx.ant.classpath}"/>
+            <echo message="Launching &lt;fx:jar&gt; task from ${ant-javafx.jar.location}" level="info"/>
+            <property name="pp_jar_destfile" value="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}"/>
+            <property name="pp_jar_buildclasses" value="${basedir}${file.separator}${build.classes.dir}"/>
+            <property name="pp_jar_cssbss" value="**${file.separator}*.${css-exclude-ext}"/>
+            <property name="pp_jar_dir" value="${jfx.deployment.dir}"/>
+            <property name="pp_jar_fs1" value="lib${file.separator}${javafx.preloader.jar.filename}"/>
+            <property name="pp_jar_fs2" value="lib${file.separator}*.jar"/>
+            <echo message="deploy_jar: pp_jar_destfile = ${pp_jar_destfile}" level="verbose"/>
+            <echo message="deploy_jar: pp_jar_buildclasses = ${pp_jar_buildclasses}" level="verbose"/>
+            <echo message="deploy_jar: pp_jar_cssbss = ${pp_jar_cssbss}" level="verbose"/>
+            <echo message="deploy_jar: pp_jar_dir = ${pp_jar_dir}" level="verbose"/>
+            <echo message="deploy_jar: pp_jar_fs1 = ${pp_jar_fs1}" level="verbose"/>
+            <echo message="deploy_jar: pp_jar_fs2 = ${pp_jar_fs2}" level="verbose"/>
+            <echo message="JavaScript: deploy-jar" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var S = java.io.File.separator;
+                    var JFXPAR = "javafx.param";
+                    var JFXPARN = "name";
+                    var JFXPARV = "value";
+                    var JFXLAZY = "download.mode.lazy.jar";
+                    var withpreloader = project.getProperty("app-with-preloader");
+                    var fx_ant_api_1_1 = project.getProperty("have-fx-ant-api-1.1");
+                    var fx_ant_api_1_2 = project.getProperty("have-fx-ant-api-1.2");
+                    var fx_in_swing_app = project.getProperty("fx-in-swing-app");
+
+                    // get jars with lazy download mode property set
+                    function getLazyJars() {
+                        var jars = new Array();
+                        var keys = project.getProperties().keys();
+                        while(keys.hasMoreElements()) {
+                            var pn = keys.nextElement();
+                            if(pn.substr(0,JFXLAZY.length) == JFXLAZY) {
+                                var fname = pn.substring(JFXLAZY.length+1);
+                                jars.push(fname);
+                            }
+                        }
+                        return jars.length > 0 ? jars : null;
+                    }
+                    // set download mode of dependent libraries
+                    function setDownloadMode(fsEager, fsLazy, jars) {
+                        for(i = 0; i < jars.length; i++) {
+                            fsEager.setExcludes("lib" + S + jars[i]);
+                            fsLazy.setIncludes("lib" + S + jars[i]);
+                        }
+                    }
+                    
+                    // fx:jar
+                    var jar = project.createTask("fx_jar");
+                    jar.setProject(project);
+                    var destfile = project.getProperty("pp_jar_destfile");
+                    jar.setDestfile(destfile);
+
+                    // fx:application
+                    var app = jar.createApplication();
+                    app.setProject(project);
+                    var title = project.getProperty("application.title");
+                    if(fx_in_swing_app == "true" && fx_ant_api_1_2 == "true") {
+                        var mainclass = project.getProperty("main.class");
+                        app.setToolkit("swing");
+                    } else {
+                        var mainclass = project.getProperty("javafx.main.class");
+                    }
+                    var fallback = project.getProperty("javafx.fallback.class");
+                    app.setName(title);
+                    app.setMainClass(mainclass);
+                    app.setFallbackClass(fallback);
+                    if(withpreloader == "true") {
+                        preloaderclass = project.getProperty("javafx.preloader.class");
+                        app.setPreloaderClass(preloaderclass);
+                    }
+                    // fx:param, fx:argument
+                    var keys = project.getProperties().keys();
+                    while(keys.hasMoreElements()) {
+                        var pn = keys.nextElement();
+                        if(pn.substr(0,JFXPAR.length) == JFXPAR && pn.indexOf(JFXPARN) == (pn.length()-JFXPARN.length)) {
+                            var propn = project.getProperty(pn);
+                            if(propn != null && propn.length() > 0) {
+                                var pv = pn.substr(0,pn.indexOf(JFXPARN)) + JFXPARV;
+                                var propv = project.getProperty(pv);
+                                if(propv != null && propv.length() > 0) {
+                                    var par = app.createParam();
+                                    par.setName(propn);
+                                    par.setValue(propv);
+                                } else {
+                                    if(fx_ant_api_1_1 == "true") {
+                                        var arg = app.createArgument();
+                                        arg.addText(propn);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    
+                    // fx:resources
+                    var res = jar.createResources();
+                    res.setProject(project);
+                    var pdir = project.getProperty("pp_jar_dir");
+                    if(withpreloader == "true") {
+                        var f1 = res.createFileSet();
+                        f1.setProject(project);
+                        f1.setDir(new java.io.File(pdir));
+                        var i1 = project.getProperty("pp_jar_fs1");
+                        f1.setIncludes(i1);
+                        f1.setRequiredFor("preloader");
+                        var f2 = res.createFileSet();
+                        f2.setProject(project);
+                        f2.setDir(new java.io.File(pdir));
+                        var i2a = project.getProperty("jfx.deployment.jar");
+                        var i2b = project.getProperty("pp_jar_fs2");
+                        var e2c = project.getProperty("pp_jar_fs1");
+                        f2.setIncludes(i2a);
+                        f2.setIncludes(i2b);
+                        f2.setExcludes(e2c);
+                        f2.setRequiredFor("startup");
+                        var lazyjars = getLazyJars();
+                        if(lazyjars != null) {
+                            var f3 = res.createFileSet();
+                            f3.setProject(project);
+                            f3.setDir(new java.io.File(pdir));
+                            f3.setRequiredFor("runtime");
+                            setDownloadMode(f2,f3,lazyjars);
+                        }
+                    } else {
+                        var fn = res.createFileSet();
+                        fn.setProject(project);
+                        fn.setDir(new java.io.File(pdir));
+                        var ia = project.getProperty("jfx.deployment.jar");
+                        var ib = project.getProperty("pp_jar_fs2");
+                        fn.setIncludes(ia);
+                        fn.setIncludes(ib);
+                        fn.setRequiredFor("startup");
+                        var lazyjars = getLazyJars();
+                        if(lazyjars != null) {
+                            var fn2 = res.createFileSet();
+                            fn2.setProject(project);
+                            fn2.setDir(new java.io.File(pdir));
+                            fn2.setRequiredFor("runtime");
+                            setDownloadMode(fn,fn2,lazyjars);
+                        }
+                    }
+                    
+                    // fileset to exclude *.css or *.bss
+                    var fs = jar.createFileSet();
+                    fs.setProject(project);
+                    var buildcls = project.getProperty("pp_jar_buildclasses");
+                    var exc = project.getProperty("pp_jar_cssbss");
+                    fs.setDir(new java.io.File(buildcls));
+                    fs.setExcludes(exc);
+                    
+                    // manifest
+                    var man = jar.createManifest();
+                    var a1val = project.getProperty("application.vendor");
+                    var a1 = new org.apache.tools.ant.taskdefs.Manifest.Attribute();
+                    a1.setName("Implementation-Vendor");
+                    a1.setValue(a1val);
+                    man.addConfiguredAttribute(a1);
+                    var a2val = project.getProperty("application.title");
+                    var a2 = new org.apache.tools.ant.taskdefs.Manifest.Attribute();
+                    a2.setName("Implementation-Title");
+                    a2.setValue(a2val);
+                    man.addConfiguredAttribute(a2);
+                    var a3 = new org.apache.tools.ant.taskdefs.Manifest.Attribute();
+                    a3.setName("Implementation-Version");
+                    a3.setValue("1.0");
+                    man.addConfiguredAttribute(a3);
+                    
+                    jar.perform();
+                ]]>
+            </script>
+            <antcall target="-post-jfx-jar"/>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="deploy-sign">
+        <sequential>
+            <echo message="keystore=${javafx.signjar.keystore}" level="verbose"/>
+            <echo message="storepass=${javafx.signjar.storepass}" level="verbose"/>
+            <echo message="alias=${javafx.signjar.alias}" level="verbose"/>
+            <echo message="keypass=${javafx.signjar.keypass}" level="verbose"/>
+            <signjar keystore="${javafx.signjar.keystore}"
+                storepass="${javafx.signjar.storepass}"
+                alias="${javafx.signjar.alias}"
+                keypass="${javafx.signjar.keypass}">
+                <fileset dir="${jfx.deployment.dir}">
+                    <include name="${jfx.deployment.jar}"/>
+                    <include name="lib${file.separator}*.jar"/>
+                </fileset>
+            </signjar>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="deploy-sign-preloader">
+        <sequential>
+            <echo message="keystore=${javafx.signjar.keystore}" level="verbose"/>
+            <echo message="storepass=${javafx.signjar.storepass}" level="verbose"/>
+            <echo message="alias=${javafx.signjar.alias}" level="verbose"/>
+            <echo message="keypass=${javafx.signjar.keypass}" level="verbose"/>
+            <signjar keystore="${javafx.signjar.keystore}"
+                storepass="${javafx.signjar.storepass}"
+                alias="${javafx.signjar.alias}"
+                keypass="${javafx.signjar.keypass}">
+                <fileset dir="${jfx.deployment.dir}">
+                    <include name="lib${file.separator}${javafx.preloader.jar.filename}"/>
+                </fileset>
+            </signjar>
+            <signjar keystore="${javafx.signjar.keystore}"
+                storepass="${javafx.signjar.storepass}"
+                alias="${javafx.signjar.alias}"
+                keypass="${javafx.signjar.keypass}">
+                <fileset dir="${jfx.deployment.dir}">
+                    <include name="${jfx.deployment.jar}"/>
+                    <include name="lib${file.separator}*.jar"/>
+                    <exclude name="lib${file.separator}${javafx.preloader.jar.filename}"/>
+                </fileset>
+            </signjar>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="deploy-process-template">
+        <sequential>
+            <echo message="javafx.run.htmltemplate = ${javafx.run.htmltemplate}" level="verbose"/>
+            <pathconvert property="javafx.run.htmltemplate.processed">
+                <path path="${javafx.run.htmltemplate}"/>
+                <mapper>
+                     <chainedmapper>
+                          <flattenmapper/>
+                          <globmapper from="*" to="${jfx.deployment.dir}${file.separator}*" casesensitive="no"/>
+                     </chainedmapper>
+                </mapper>
+            </pathconvert>
+            <echo message="javafx.run.htmltemplate.processed = ${javafx.run.htmltemplate.processed}" level="verbose"/>
+        </sequential>
+    </macrodef>
+
+    <!-- fx:deploy scripted call enables passing of arbitrarily long lists of params, vmoptions and callbacks and fx-version dependent behavior -->
+    <macrodef name="deploy-deploy">
+        <sequential>
+            <antcall target="-pre-jfx-deploy"/>
+            <antcall target="-call-pre-jfx-native"/>
+            <echo message="javafx.ant.classpath = ${javafx.ant.classpath}" level="verbose"/>
+            <typedef name="fx_deploy" classname="com.sun.javafx.tools.ant.DeployFXTask" classpath="${javafx.ant.classpath}"/>
+            <echo message="Launching &lt;fx:deploy&gt; task from ${ant-javafx.jar.location}" level="info"/>
+            <property name="pp_deploy_dir" value="${jfx.deployment.dir}"/>
+            <property name="pp_deploy_fs1" value="lib${file.separator}${javafx.preloader.jar.filename}"/>
+            <property name="pp_deploy_fs2" value="lib${file.separator}*.jar"/>
+            <echo message="deploy_deploy: pp_deploy_dir = ${pp_deploy_dir}" level="verbose"/>
+            <echo message="deploy_deploy: pp_deploy_fs1 = ${pp_deploy_fs1}" level="verbose"/>
+            <echo message="deploy_deploy: pp_deploy_fs2 = ${pp_deploy_fs2}" level="verbose"/>
+            <echo message="JavaScript: deploy-deploy" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    function isTrue(prop) {
+                        return prop != null && 
+                           (prop.toLowerCase()=="true" || prop.toLowerCase()=="yes" || prop.toLowerCase()=="on");
+                    }                    
+                    var S = java.io.File.separator;
+                    var JFXPAR = "javafx.param";
+                    var JFXPARN = "name";
+                    var JFXPARV = "value";
+                    var JFXCALLB = "javafx.jscallback";
+                    var JFXLAZY = "download.mode.lazy.jar";
+                    var withpreloader = project.getProperty("app-with-preloader");
+                    var fx_ant_api_1_1 = project.getProperty("have-fx-ant-api-1.1");
+                    var fx_ant_api_1_2 = project.getProperty("have-fx-ant-api-1.2");
+                    var fx_in_swing_app = project.getProperty("fx-in-swing-app");
+
+                    // get jars with lazy download mode property set
+                    function getLazyJars() {
+                        var jars = new Array();
+                        var keys = project.getProperties().keys();
+                        while(keys.hasMoreElements()) {
+                            var pn = keys.nextElement();
+                            if(pn.substr(0,JFXLAZY.length) == JFXLAZY) {
+                                var fname = pn.substring(JFXLAZY.length+1);
+                                jars.push(fname);
+                            }
+                        }
+                        return jars.length > 0 ? jars : null;
+                    }
+                    // set download mode of dependent libraries
+                    function setDownloadMode(fsEager, fsLazy, jars) {
+                        for(i = 0; i < jars.length; i++) {
+                            fsEager.setExcludes("lib" + S + jars[i]);
+                            fsLazy.setIncludes("lib" + S + jars[i]);
+                        }
+                    }
+                    
+                    // fx:deploy
+                    var deploy = project.createTask("fx_deploy");
+                    deploy.setProject(project);
+                    var width = project.getProperty("javafx.width");
+                    var height = project.getProperty("javafx.height");
+                    var outdir = project.getProperty("jfx.deployment.dir");
+                    var embedJNLP = project.getProperty("javafx.deploy.embedJNLP");
+                    var updatemode = project.getProperty("update-mode");
+                    var outfile = project.getProperty("application.title");
+                    var includeDT = project.getProperty("javafx.deploy.includeDT");
+                    var offline = project.getProperty("javafx.deploy.allowoffline");
+                    deploy.setWidth(width);
+                    deploy.setHeight(height);
+                    deploy.setOutdir(outdir);
+                    deploy.setEmbedJNLP(isTrue(embedJNLP));
+                    deploy.setUpdateMode(updatemode);
+                    deploy.setOutfile(outfile);
+                    deploy.setIncludeDT(isTrue(includeDT));
+                    if(offline != null) {
+                        if(fx_ant_api_1_1 == "true") {
+                            deploy.setOfflineAllowed(isTrue(offline));
+                        } else {
+                            println("Warning: offlineAllowed not supported by this version of JavaFX SDK deployment Ant task. Please upgrade JavaFX to 2.0.2 or higher.");
+                        }
+                    }
+                    // native packaging (time consuming, thus applied in explicit build only)
+                    var nativeEnabled = project.getProperty("do.build.native.package");
+                    var nativeType = project.getProperty("javafx.native.bundling.type");
+                    var projStateRun = project.getProperty("project.state.running");
+                    var projStateDbg = project.getProperty("project.state.debugging");
+                    var projStatePrf = project.getProperty("project.state.profiling");
+                    if(isTrue(nativeEnabled) && nativeType != null && nativeType != "none") {
+                        if(!isTrue(projStateRun) && !isTrue(projStateDbg) && !isTrue(projStatePrf)) {
+                            if(fx_ant_api_1_2 == "true") {
+                                deploy.setNativeBundles(nativeType);
+                                println("Note: To create native bundles the <fx:deploy> task may require external tools. See JavaFX 2.2+ documentation for details.");
+                                println("");
+                                println("Launching <fx:deploy> in native packager mode...");
+                            } else {
+                                println("Warning: Native packaging is not supported by this version of JavaFX SDK deployment Ant task. Please upgrade to JDK 7u6 or higher.");
+                            }
+                        }
+                    }
+
+                    // fx:application
+                    var app = deploy.createApplication();
+                    app.setProject(project);
+                    var title = project.getProperty("application.title");
+                    if(fx_in_swing_app == "true" && fx_ant_api_1_2 == "true") {
+                        var mainclass = project.getProperty("main.class");
+                        app.setToolkit("swing");
+                    } else {
+                        var mainclass = project.getProperty("javafx.main.class");
+                    }
+                    var fallback = project.getProperty("javafx.fallback.class");
+                    app.setName(title);
+                    app.setMainClass(mainclass);
+                    app.setFallbackClass(fallback);
+                    if(withpreloader == "true") {
+                        preloaderclass = project.getProperty("javafx.preloader.class");
+                        app.setPreloaderClass(preloaderclass);
+                    }
+                    // fx:param, fx:argument
+                    var keys = project.getProperties().keys();
+                    while(keys.hasMoreElements()) {
+                        var pn = keys.nextElement();
+                        if(pn.substr(0,JFXPAR.length) == JFXPAR && pn.indexOf(JFXPARN) == (pn.length()-JFXPARN.length)) {
+                            var propn = project.getProperty(pn);
+                            if(propn != null && propn.length() > 0) {
+                                var pv = pn.substr(0,pn.indexOf(JFXPARN)) + JFXPARV;
+                                var propv = project.getProperty(pv);
+                                if(propv != null && propv.length() > 0) {
+                                    var par = app.createParam();
+                                    par.setName(propn);
+                                    par.setValue(propv);
+                                } else {
+                                    if(fx_ant_api_1_1 == "true") {
+                                        var arg = app.createArgument();
+                                        arg.addText(propn);
+                                    } else {
+                                        println("Warning: Unnamed parameters not supported by this version of JavaFX SDK deployment Ant tasks. Upgrade JavaFX to 2.0.2 or higher.");
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    
+                    // fx:resources
+                    var res = deploy.createResources();
+                    res.setProject(project);
+                    var deploydir = project.getProperty("pp_deploy_dir");
+                    if(withpreloader == "true") {
+                        var f1 = res.createFileSet();
+                        f1.setProject(project);
+                        f1.setDir(new java.io.File(deploydir));
+                        var i1 = project.getProperty("pp_deploy_fs1");
+                        f1.setIncludes(i1);
+                        f1.setRequiredFor("preloader");
+                        var f2 = res.createFileSet();
+                        f2.setProject(project);
+                        f2.setDir(new java.io.File(deploydir));
+                        var i2a = project.getProperty("jfx.deployment.jar");
+                        var i2b = project.getProperty("pp_deploy_fs2");
+                        var e2c = project.getProperty("pp_deploy_fs1");
+                        f2.setIncludes(i2a);
+                        f2.setIncludes(i2b);
+                        f2.setExcludes(e2c);
+                        f2.setRequiredFor("startup");
+                        var lazyjars = getLazyJars();
+                        if(lazyjars != null) {
+                            var f3 = res.createFileSet();
+                            f3.setProject(project);
+                            f3.setDir(new java.io.File(deploydir));
+                            f3.setRequiredFor("runtime");
+                            setDownloadMode(f2,f3,lazyjars);
+                        }
+                    } else {
+                        var fn = res.createFileSet();
+                        fn.setProject(project);
+                        fn.setDir(new java.io.File(deploydir));
+                        var ia = project.getProperty("jfx.deployment.jar");
+                        var ib = project.getProperty("pp_deploy_fs2");
+                        fn.setIncludes(ia);
+                        fn.setIncludes(ib);
+                        fn.setRequiredFor("startup");
+                        var lazyjars = getLazyJars();
+                        if(lazyjars != null) {
+                            var fn2 = res.createFileSet();
+                            fn2.setProject(project);
+                            fn2.setDir(new java.io.File(deploydir));
+                            fn2.setRequiredFor("runtime");
+                            setDownloadMode(fn,fn2,lazyjars);
+                        }
+                    }
+                    
+                    // fx:info
+                    var info = deploy.createInfo();
+                    info.setProject(project);
+                    var vendor = project.getProperty("application.vendor");
+                    var description = project.getProperty("application.desc");
+                    info.setTitle(title); // title known from before
+                    info.setVendor(vendor);
+                    info.setDescription(description);
+                    var icon = project.getProperty("javafx.deploy.icon");
+                    if(icon != null) {
+                        if(fx_ant_api_1_1 == "true") {
+                            var iicon = info.createIcon();
+                            iicon.setHref(icon);
+                        } else {
+                            println("Warning: Icon not supported by this version of JavaFX SDK deployment Ant task. Please upgrade JavaFX to 2.0.2 or higher.");
+                        }
+                    }
+                    
+                    // fx:permissions
+                    var perm = deploy.createPermissions();
+                    perm.setProject(project);
+                    var elev = project.getProperty("permissions.elevated");
+                    perm.setElevated(isTrue(elev));
+                    
+                    // fx:preferences
+                    var pref = deploy.createPreferences();
+                    pref.setProject(project);
+                    var scut = project.getProperty("javafx.deploy.adddesktopshortcut");
+                    var instp = project.getProperty("javafx.deploy.installpermanently");
+                    var smenu = project.getProperty("javafx.deploy.addstartmenushortcut");
+                    pref.setShortcut(isTrue(scut));
+                    pref.setInstall(isTrue(instp));
+                    pref.setMenu(isTrue(smenu));
+
+                    // fx:template
+                    var templ = project.getProperty("javafx.run.htmltemplate");
+                    var templp = project.getProperty("javafx.run.htmltemplate.processed");
+                    if(templ != null && templp != null && templ.length() > 0 && templp.length() > 0) {
+                        var temp = deploy.createTemplate();
+                        temp.setProject(project);
+                        temp.setFile(new java.io.File(templ));
+                        temp.setTofile(new java.io.File(templp));
+                    }
+
+                    // fx:platform
+                    var plat = deploy.createPlatform();
+                    plat.setProject(project);
+                    var jvmargs = project.getProperty("run.jvmargs");
+                    if(jvmargs != null && jvmargs.length() > 0) {
+                        var jvmargss = jvmargs.split(" ");
+                        for(i = 0; i < jvmargss.length; i++) {
+                            if(jvmargss[i] != null && jvmargss[i].length() > 0) {
+                                var vmarg = plat.createJvmarg();
+                                vmarg.setValue(jvmargss[i]);
+                            }
+                        }
+                    }
+                    
+                    // fx:callbacks
+                    var callbs = deploy.createCallbacks();
+                    callbs.setProject(project);
+                    var keys = project.getProperties().keys();
+                    while(keys.hasMoreElements()) {
+                        var pn = keys.nextElement();
+                        if(pn.substr(0,JFXCALLB.length) == JFXCALLB) {
+                            var prop = project.getProperty(pn);
+                            if(prop != null && prop.length() > 0) {
+                                var cname = pn.substring(JFXCALLB.length+1);
+                                var cb = callbs.createCallback();
+                                cb.setProject(project);
+                                cb.setName(cname);
+                                cb.addText(prop);
+                            }
+                        }
+                    }
+                    
+                    deploy.perform();
+                ]]>
+            </script>
+            <antcall target="-post-jfx-deploy"/>
+            <antcall target="-call-post-jfx-native"/>
+        </sequential>
+    </macrodef>
+
+    <!-- JavaFX SDK 2.0.x and 2.1.x deploy task can not generate pre-FX jnlp which is needed for FX-in-Swing projects-->
+    <macrodef name="deploy-deploy-swing">
+        <sequential>
+            <antcall target="-pre-jfx-deploy"/>
+            <local name="permissions-elevated-token"/>
+            <condition property="permissions-elevated-token" value="${line.separator}    &lt;security&gt;${line.separator}        &lt;all-permissions/&gt;${line.separator}    &lt;/security&gt;" else="">
+                <isset property="permissions-elevated"/>
+            </condition>
+            <local name="offline-allowed-token"/>
+            <condition property="offline-allowed-token" value="${line.separator}        &lt;offline-allowed/&gt;" else="">
+                <isset property="offline-allowed"/>
+            </condition>
+            <local name="update-mode-background-token"/>
+            <condition property="update-mode-background-token" value="background" else="always">
+                <isset property="update-mode-background"/>
+            </condition>
+            <local name="html-template-processed-available"/>
+            <condition property="html-template-processed-available">
+                <and>
+                    <isset property="javafx.run.htmltemplate.processed"/>
+                    <not>
+                        <equals arg1="${javafx.run.htmltemplate.processed}" arg2=""/>
+                    </not>
+                </and>
+            </condition>
+            <local name="javafx.deploy.icon.basename"/>
+            <basename property="javafx.deploy.icon.basename" file="${javafx.deploy.icon}"/>
+            <local name="local-icon-filename-available"/>
+            <condition property="local-icon-filename-available">
+                <and>
+                    <isset property="icon-available"/>
+                    <isset property="javafx.deploy.icon.basename"/>
+                    <not><equals arg1="${javafx.deploy.icon.basename}" arg2=""/></not>
+                    <not><contains string="${javafx.deploy.icon.basename}" substring="$${javafx" casesensitive="false"/></not>
+                    <not><contains string="${javafx.deploy.icon}" substring="http:" casesensitive="false"/></not>
+                </and>
+            </condition>
+            <local name="icon-token"/>
+            <condition property="icon-token" value="${line.separator}        &lt;icon href=&quot;${javafx.deploy.icon.basename}&quot; kind=&quot;default&quot;/&gt;">
+                <isset property="local-icon-filename-available"/>
+            </condition>
+            <condition property="icon-token" value="${line.separator}        &lt;icon href=&quot;${javafx.deploy.icon}&quot; kind=&quot;default&quot;/&gt;" else="">
+                <isset property="icon-available"/>
+            </condition>
+            <basename property="dist.filename" file="${dist.jar}" suffix=".jar"/>
+            <length file="${dist.jar}" property="dist.jar.size" />
+            <local name="vmargs-token"/>
+            <condition property="vmargs-token" value="java-vm-args=&quot;${run.jvmargs}&quot; " else="">
+                <isset property="vmargs-available"/>
+            </condition>
+            <local name="applet-params-token"/>
+            <local name="application-args-token"/>
+            <echo message="JavaScript: deploy-deploy-swing 1" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var JFXPAR = "javafx.param";
+                    var JFXPARN = "name";
+                    var JFXPARV = "value";
+
+                    var params = "";
+                    var args = "";
+                    var keys = project.getProperties().keys();
+                    while(keys.hasMoreElements()) {
+                        var pn = keys.nextElement();
+                        if(pn.substr(0,JFXPAR.length) == JFXPAR && pn.indexOf(JFXPARN) == (pn.length()-JFXPARN.length)) {
+                            var propn = project.getProperty(pn);
+                            if(propn != null && propn.length() > 0) {
+                                var pv = pn.substr(0,pn.indexOf(JFXPARN)) + JFXPARV;
+                                var propv = project.getProperty(pv);
+                                if(propv != null && propv.length() > 0) {
+                                    params += "\n        <param name=\"" + propn + "\" value=\"" + propv + "\"/>";
+                                    args += "\n        <argument>" + propn + "=" + propv + "</argument>";
+                                } else {
+                                    params += "\n        <param name=\"" + propn + "\" value=\"\"/>";
+                                    args += "\n        <argument>" + propn + "</argument>";
+                                }
+                            }
+                        }
+                    }
+                    project.setProperty("applet-params-token", params);
+                    project.setProperty("application-args-token", args);
+                ]]>
+            </script>
+            <local name="application.desc.processed"/>
+            <condition property="application.desc.processed" value="${application.desc}" else="Swing applet embedding JavaFX components.">
+                <isset property="application.desc"/>
+            </condition>
+            <filterchain id="jnlp.template.filter">
+                <replacetokens>
+                    <token key="NAME" value="${dist.filename}"/>
+                    <token key="MAINCLASS" value="${main.class}"/>
+                    <token key="FILESIZE" value="${dist.jar.size}"/>
+                    <token key="VENDOR" value="${application.vendor}"/>
+                    <token key="TITLE" value="${application.title}"/>
+                    <token key="DESCRIPTION" value="${application.desc.processed}"/>
+                    <token key="WIDTH" value="${javafx.run.width}"/>
+                    <token key="HEIGHT" value="${javafx.run.height}"/>
+                    <token key="PERMISSIONS" value="${permissions-elevated-token}"/>
+                    <token key="OFFLINE" value="${offline-allowed-token}"/>
+                    <token key="UPDATEMODE" value="${update-mode-background-token}"/>
+                    <token key="ICON" value="${icon-token}"/>
+                    <token key="VMARGS" value="${vmargs-token}"/>
+                    <token key="PARAMETERS" value="${applet-params-token}"/>
+                    <token key="ARGUMENTS" value="${application-args-token}"/>
+                </replacetokens>
+            </filterchain>
+            <copy file="${basedir}${file.separator}nbproject${file.separator}templates${file.separator}FXSwingTemplateApplication.jnlp" 
+                    tofile="${dist.dir}${file.separator}${dist.filename}_application.jnlp" >
+                    <filterchain refid="jnlp.template.filter"/>
+            </copy>        
+            <copy file="${basedir}${file.separator}nbproject${file.separator}templates${file.separator}FXSwingTemplateApplet.jnlp" 
+                    tofile="${dist.dir}${file.separator}${dist.filename}_applet.jnlp" >
+                    <filterchain refid="jnlp.template.filter"/>
+            </copy>        
+            <copy file="${basedir}${file.separator}nbproject${file.separator}templates${file.separator}FXSwingTemplate.html" 
+                    tofile="${dist.dir}${file.separator}${dist.filename}.html" >
+                    <filterchain refid="jnlp.template.filter"/>
+            </copy>
+            <echo message="JavaScript: deploy-deploy-swing 2" level="verbose"/>
+            <script language="javascript">
+                <![CDATA[
+                    var PREF = "file:";
+                    var doCopyIcon = project.getProperty("local-icon-filename-available");
+                    if(doCopyIcon != null) {
+                        var iconProp = project.getProperty("javafx.deploy.icon");
+                        if(iconProp.indexOf(PREF) == 0) {
+                            iconProp = iconProp.slice(PREF.length);
+                        }
+                        while(iconProp.charAt(0) == "/") {
+                            iconProp = iconProp.slice(1);
+                        }
+                        var S = java.io.File.separator;
+                        var baseDir = project.getProperty("basedir");
+                        var distDir = project.getProperty("dist.dir");
+                        var copyTask = project.createTask("copy");
+                        var source = new java.io.File(iconProp);
+                        var target = new java.io.File(baseDir + S + distDir);
+                        copyTask.setFile(source);
+                        copyTask.setTodir(target);
+                        copyTask.setFlatten(true);
+                        copyTask.setFailOnError(false);
+                        copyTask.perform();
+                    }
+                    var doCopyHTMLFrom = project.getProperty("html-template-available");
+                    var doCopyHTMLTo = project.getProperty("html-template-processed-available");
+                    if(doCopyHTMLFrom != null && doCopyHTMLTo != null) {
+                        var htmlFrom = project.getProperty("javafx.run.htmltemplate");
+                        if(htmlFrom.indexOf(PREF) == 0) {
+                            htmlFrom = htmlFrom.slice(PREF.length);
+                        }
+                        while(htmlFrom.charAt(0) == "/") {
+                            htmlFrom = htmlFrom.slice(1);
+                        }
+                        var htmlTo = project.getProperty("javafx.run.htmltemplate.processed");
+                        if(htmlTo.indexOf(PREF) == 0) {
+                            htmlTo = htmlTo.slice(PREF.length);
+                        }
+                        while(htmlTo.charAt(0) == "/") {
+                            htmlTo = htmlTo.slice(1);
+                        }
+                        var copyTask = project.createTask("copy");
+                        var source = new java.io.File(htmlFrom);
+                        var target = new java.io.File(htmlTo);
+                        copyTask.setFile(source);
+                        copyTask.setTofile(target);
+                        copyTask.setFailOnError(false);
+                        copyTask.perform();
+                    }
+                ]]>
+            </script>
+            <antcall target="-post-jfx-deploy"/>
+        </sequential>
+    </macrodef>
+
+
+    <!-- Fallback Project Deployment Macros To Support At Least Partially JDKs Without JavaScript Support -->
+    
+    <macrodef name="fallback-deploy-application-def">
+        <sequential>
+            <echo message="Warning: Parameters (if any) not passed to &lt;fx:application&gt; in fallback build mode due to JDK missing JavaScript support."/>
+            <fx:application id="fxApp"
+                name="${application.title}"
+                mainClass="${javafx.main.class}"
+                fallbackClass="${javafx.fallback.class}">
+                <!-- PARAMETERS NOT PASSED IN FALLBACK -->
+            </fx:application>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-application-def-preloader">
+        <sequential>
+            <echo message="Warning: Parameters (if any) not passed to &lt;fx:application&gt; in fallback build mode due to JDK missing JavaScript support."/>
+            <fx:application id="fxApp"
+                name="${application.title}"
+                mainClass="${javafx.main.class}"
+                preloaderClass="${javafx.preloader.class}"
+                fallbackClass="${javafx.fallback.class}">
+                <!-- PARAMETERS NOT PASSED IN FALLBACK -->
+            </fx:application>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-application-def-swing">
+        <sequential>
+            <echo message="Warning: Parameters (if any) not passed to &lt;fx:application&gt; in fallback build mode due to JDK missing JavaScript support."/>
+            <fx:application id="fxApp"
+                name="${application.title}"
+                mainClass="${main.class}"
+                fallbackClass="${javafx.fallback.class}"
+                toolkit="swing">
+                <!-- PARAMETERS NOT PASSED IN FALLBACK -->
+            </fx:application>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-resources">
+        <sequential>
+            <fx:resources id="appRes">
+                <fx:fileset requiredFor="startup" dir="${jfx.deployment.dir}">
+                    <include name="${jfx.deployment.jar}"/>
+                    <include name="lib${file.separator}*.jar"/>
+                    <exclude name="lib${file.separator}${jfx.deployment.jar}"/>
+                </fx:fileset>
+            </fx:resources>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-resources-preloader">
+        <sequential>
+            <fx:resources id="appRes">
+                <fx:fileset requiredFor="preloader" dir="${jfx.deployment.dir}">
+                    <include name="lib${file.separator}${javafx.preloader.jar.filename}"/>
+                </fx:fileset>
+                <fx:fileset requiredFor="startup" dir="${jfx.deployment.dir}">
+                    <include name="${jfx.deployment.jar}"/>
+                    <include name="lib${file.separator}*.jar"/>
+                    <exclude name="lib${file.separator}${javafx.preloader.jar.filename}"/>
+                    <exclude name="lib${file.separator}${jfx.deployment.jar}"/>
+                </fx:fileset>
+            </fx:resources>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-jar">
+        <sequential>
+            <antcall target="-pre-jfx-jar"/>
+            <fx:jar destfile="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}">
+                <fx:application refid="fxApp"/>
+                <fx:resources refid="appRes"/>
+                <fileset dir="${build.classes.dir}">
+                    <exclude name="**${file.separator}*.${css-exclude-ext}"/>
+                </fileset>
+                <manifest>
+                    <attribute name="Implementation-Vendor" value="${application.vendor}"/>
+                    <attribute name="Implementation-Title" value="${application.title}"/>
+                    <attribute name="Implementation-Version" value="1.0"/>
+                </manifest>
+            </fx:jar>
+            <antcall target="-post-jfx-jar"/>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-deploy">
+        <sequential>
+            <antcall target="-pre-jfx-deploy"/>
+            <echo message="Warning: JVM Arguments and Callbacks (if any) not passed to &lt;fx:deploy&gt; in fallback build mode due to JDK missing JavaScript support."/>
+            <fx:deploy width="${javafx.width}" height="${javafx.height}"
+                      outdir="${jfx.deployment.dir}" embedjnlp="true" updatemode="${update-mode}"
+                      outfile="${application.title}" includeDT="${javafx.deploy.includeDT}">
+                <fx:application refid="fxApp"/>
+                <fx:resources refid="appRes"/>
+                <fx:info title="${application.title}" vendor="${application.vendor}"/>
+                <fx:permissions elevated="${permissions.elevated}"/>
+                <fx:preferences shortcut="${javafx.deploy.adddesktopshortcut}" install="${javafx.deploy.installpermanently}" menu="${javafx.deploy.addstartmenushortcut}"/>
+                <!-- PLATFORM NOT PASSED IN FALLBACK -->
+                <!-- CALLBACKS NOT PASSED IN FALLBACK -->
+            </fx:deploy>
+            <antcall target="-post-jfx-deploy"/>
+        </sequential>
+    </macrodef>
+
+    <macrodef name="fallback-deploy-deploy-template">
+        <sequential>
+            <antcall target="-pre-jfx-deploy"/>
+            <echo message="Warning: JVM Arguments and Callbacks (if any) not passed to &lt;fx:deploy&gt; in fallback build mode due to JDK missing JavaScript support."/>
+            <deploy-process-template/>
+            <fx:deploy width="${javafx.width}" height="${javafx.height}"
+                      outdir="${jfx.deployment.dir}" embedjnlp="true" updatemode="${update-mode}"
+                      outfile="${application.title}" includeDT="${javafx.deploy.includeDT}">
+                <fx:application refid="fxApp"/>
+                <fx:resources refid="appRes"/>
+                <fx:info title="${application.title}" vendor="${application.vendor}"/>
+                <fx:permissions elevated="${permissions.elevated}"/>
+                <fx:preferences shortcut="${javafx.deploy.adddesktopshortcut}" install="${javafx.deploy.installpermanently}" menu="${javafx.deploy.addstartmenushortcut}"/>
+                <fx:template file="${javafx.run.htmltemplate}" tofile="${javafx.run.htmltemplate.processed}"/>
+                <!-- PLATFORM NOT PASSED IN FALLBACK -->
+                <!-- CALLBACKS NOT PASSED IN FALLBACK -->
+            </fx:deploy>
+            <antcall target="-post-jfx-deploy"/>
+        </sequential>
+    </macrodef>
+
+
+    <!-- Project Deployment Targets -->
+
+    <target name="-check-sign" depends="-check-project,-javafx-init-keystore" if="javafx.signed.true+signjars.task.available">
+        <condition property="sign-nopreloader-notemplate">
+            <and>
+                <isset property="app-without-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="sign-preloader-notemplate">
+            <and>
+                <isset property="app-with-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="sign-nopreloader-template">
+            <and>
+                <isset property="app-without-preloader"/>
+                <isset property="html-template-available"/>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="sign-preloader-template">
+            <and>
+                <isset property="app-with-preloader"/>
+                <isset property="html-template-available"/>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="sign-nopreloader-notemplate-swing">
+            <and>
+                <isset property="app-without-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <isset property="fx-in-swing-app-workaround"/>
+            </and>
+        </condition>
+        <condition property="sign-nopreloader-template-swing">
+            <and>
+                <isset property="app-without-preloader"/>
+                <isset property="html-template-available"/>
+                <isset property="fx-in-swing-app-workaround"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-check-nosign" depends="-check-project">
+        <condition property="nosign-nopreloader-notemplate">
+            <and>
+                <isset property="app-without-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <not><isset property="javafx.signed.true"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="nosign-preloader-notemplate">
+            <and>
+                <isset property="app-with-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <not><isset property="javafx.signed.true"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="nosign-nopreloader-template">
+            <and>
+                <isset property="app-without-preloader"/>
+                <isset property="html-template-available"/>
+                <not><isset property="javafx.signed.true"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="nosign-preloader-template">
+            <and>
+                <isset property="app-with-preloader"/>
+                <isset property="html-template-available"/>
+                <not><isset property="javafx.signed.true"/></not>
+                <not><isset property="fx-in-swing-app-workaround"/></not>
+            </and>
+        </condition>
+        <condition property="nosign-nopreloader-notemplate-swing">
+            <and>
+                <isset property="app-without-preloader"/>
+                <not><isset property="html-template-available"/></not>
+                <not><isset property="javafx.signed.true"/></not>
+                <isset property="fx-in-swing-app-workaround"/>
+            </and>
+        </condition>
+        <condition property="nosign-nopreloader-template-swing">
+            <and>
+                <isset property="app-without-preloader"/>
+                <isset property="html-template-available"/>
+                <not><isset property="javafx.signed.true"/></not>
+                <isset property="fx-in-swing-app-workaround"/>
+            </and>
+        </condition>
+    </target>
+
+
+    <!-- WITH SIGNING -->
+
+    <!-- project without preloader -->
+    <!-- no html template -->
+    <target name="-deploy-app-sign-nopreloader-notemplate" depends="-check-sign" if="sign-nopreloader-notemplate" unless="preloader-app">
+        <echo message="-deploy-app-sign-nopreloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project with preloader -->
+    <!-- no html template -->
+    <target name="-deploy-app-sign-preloader-notemplate" depends="-check-sign" if="sign-preloader-notemplate" unless="preloader-app">
+        <echo message="-deploy-app-sign-preloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign-preloader/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- html template -->
+    <target name="-deploy-app-sign-nopreloader-template" depends="-check-sign" if="sign-nopreloader-template" unless="preloader-app">
+        <echo message="-deploy-app-sign-nopreloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign/>
+        <deploy-process-template/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project with preloader -->
+    <!-- html template -->
+    <target name="-deploy-app-sign-preloader-template" depends="-check-sign" if="sign-preloader-template" unless="preloader-app">
+        <echo message="-deploy-app-sign-preloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign-preloader/>
+        <deploy-process-template/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- no html template -->
+    <!-- FX in Swing app -->
+    <target name="-deploy-app-sign-nopreloader-notemplate-swing" depends="-check-sign" if="sign-nopreloader-notemplate-swing" unless="preloader-app-no-workaround">
+        <echo message="-deploy-app-sign-nopreloader-notemplate-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign/>
+        <deploy-deploy-swing/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- html template -->
+    <!-- FX in Swing app -->
+    <target name="-deploy-app-sign-nopreloader-template-swing" depends="-check-sign" if="sign-nopreloader-template-swing" unless="preloader-app-no-workaround">
+        <echo message="-deploy-app-sign-nopreloader-template-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-sign/>
+        <deploy-process-template/>
+        <deploy-deploy-swing/>
+    </target>
+
+
+    <!-- NO SIGNING -->
+
+    <!-- project without preloader -->
+    <!-- no html template -->
+    <target name="-deploy-app-nosign-nopreloader-notemplate" depends="-check-nosign" if="nosign-nopreloader-notemplate" unless="preloader-app">
+        <echo message="-deploy-app-nosign-nopreloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project with preloader -->
+    <!-- no html template -->
+    <target name="-deploy-app-nosign-preloader-notemplate" depends="-check-nosign" if="nosign-preloader-notemplate" unless="preloader-app">
+        <echo message="-deploy-app-nosign-preloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- html template -->
+    <target name="-deploy-app-nosign-nopreloader-template" depends="-check-nosign" if="nosign-nopreloader-template" unless="preloader-app">
+        <echo message="-deploy-app-nosign-nopreloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-process-template/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project with preloader -->
+    <!-- html template -->
+    <target name="-deploy-app-nosign-preloader-template" depends="-check-nosign" if="nosign-preloader-template" unless="preloader-app">
+        <echo message="-deploy-app-nosign-preloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-process-template/>
+        <deploy-deploy/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- no html template -->
+    <!-- FX in Swing app -->
+    <target name="-deploy-app-nosign-nopreloader-notemplate-swing" depends="-check-nosign" if="nosign-nopreloader-notemplate-swing" unless="preloader-app-no-workaround">
+        <echo message="-deploy-app-nosign-nopreloader-notemplate-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-deploy-swing/>
+    </target>
+
+    <!-- project without preloader -->
+    <!-- html template -->
+    <!-- FX in Swing app -->
+    <target name="-deploy-app-nosign-nopreloader-template-swing" depends="-check-nosign" if="nosign-nopreloader-template-swing" unless="preloader-app-no-workaround">
+        <echo message="-deploy-app-nosign-nopreloader-template-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <deploy-jar/>
+        <deploy-process-template/>
+        <deploy-deploy-swing/>
+    </target>
+
+
+    <!-- FALLBACK (NO JAVASCRIPT) TARGETS WITH SIGNING -->
+
+    <target name="-check-fallback-sign-deploy-swing-possible" depends="-check-sign">
+        <local name="fail-deploy-swing-possible"/>
+        <condition property="fail-deploy-swing-possible">
+            <and>
+                <or>
+                    <isset property="sign-nopreloader-notemplate-swing"/>
+                    <isset property="sign-nopreloader-template-swing"/>
+                </or>
+                <not><isset property="have-fx-ant-api-1.2"/></not>
+            </and>
+        </condition>
+        <fail message="Error: JavaFX SDK version 2.2 or newer is needed to deploy FX-in-Swing on JDK without JavaScript support." 
+              if="fail-deploy-swing-possible"/>
+    </target>
+    
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK no html template -->
+    <target name="-fallback-deploy-app-sign-nopreloader-notemplate" depends="-check-sign" if="sign-nopreloader-notemplate" unless="preloader-app">
+        <echo message="-fallback-deploy-app-sign-nopreloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <deploy-sign/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project with preloader -->
+    <!-- FALLBACK no html template -->
+    <target name="-fallback-deploy-app-sign-preloader-notemplate" depends="-check-sign" if="sign-preloader-notemplate" unless="preloader-app">
+        <echo message="-fallback-deploy-app-sign-preloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-preloader/>
+        <fallback-deploy-resources-preloader/>
+        <fallback-deploy-jar/>
+        <deploy-sign-preloader/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK html template -->
+    <target name="-fallback-deploy-app-sign-nopreloader-template" depends="-check-sign" if="sign-nopreloader-template" unless="preloader-app">
+        <echo message="-fallback-deploy-app-sign-nopreloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <deploy-sign/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+    <!-- FALLBACK project with preloader -->
+    <!-- FALLBACK html template -->
+    <target name="-fallback-deploy-app-sign-preloader-template" depends="-check-sign" if="sign-preloader-template" unless="preloader-app">
+        <echo message="-fallback-deploy-app-sign-preloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-preloader/>
+        <fallback-deploy-resources-preloader/>
+        <fallback-deploy-jar/>
+        <deploy-sign-preloader/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK no html template -->
+    <!-- FALLBACK FX in Swing app -->
+    <target name="-fallback-deploy-app-sign-nopreloader-notemplate-swing" depends="-check-fallback-sign-deploy-swing-possible" if="sign-nopreloader-notemplate-swing" unless="preloader-app-no-workaround">
+        <echo message="-fallback-deploy-app-sign-nopreloader-notemplate-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-swing/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <deploy-sign/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK html template -->
+    <!-- FALLBACK FX in Swing app -->
+    <target name="-fallback-deploy-app-sign-nopreloader-template-swing" depends="-check-fallback-sign-deploy-swing-possible" if="sign-nopreloader-template-swing" unless="preloader-app-no-workaround">
+        <echo message="-fallback-deploy-app-sign-nopreloader-template-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-swing/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <deploy-sign/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+
+    <!-- FALLBACK (NO JAVASCRIPT) TARGETS NO SIGNING -->
+
+    <target name="-check-fallback-nosign-deploy-swing-possible" depends="-check-nosign">
+        <local name="fail-deploy-swing-possible"/>
+        <condition property="fail-deploy-swing-possible">
+            <and>
+                <or>
+                    <isset property="nosign-nopreloader-notemplate-swing"/>
+                    <isset property="nosign-nopreloader-template-swing"/>
+                </or>
+                <not><isset property="have-fx-ant-api-1.2"/></not>
+            </and>
+        </condition>
+        <fail message="Error: JavaFX SDK version 2.2 or newer is needed to deploy FX-in-Swing on JDK without JavaScript support." 
+              if="fail-deploy-swing-possible"/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK no html template -->
+    <target name="-fallback-deploy-app-nosign-nopreloader-notemplate" depends="-check-nosign" if="nosign-nopreloader-notemplate" unless="preloader-app">
+        <echo message="-fallback-deploy-app-nosign-nopreloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project with preloader -->
+    <!-- FALLBACK no html template -->
+    <target name="-fallback-deploy-app-nosign-preloader-notemplate" depends="-check-nosign" if="nosign-preloader-notemplate" unless="preloader-app">
+        <echo message="-fallback-deploy-app-nosign-preloader-notemplate" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-preloader/>
+        <fallback-deploy-resources-preloader/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK html template -->
+    <target name="-fallback-deploy-app-nosign-nopreloader-template" depends="-check-nosign" if="nosign-nopreloader-template" unless="preloader-app">
+        <echo message="-fallback-deploy-app-nosign-nopreloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+    <!-- FALLBACK project with preloader -->
+    <!-- FALLBACK html template -->
+    <target name="-fallback-deploy-app-nosign-preloader-template" depends="-check-nosign" if="nosign-preloader-template" unless="preloader-app">
+        <echo message="-fallback-deploy-app-nosign-preloader-template" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-preloader/>
+        <fallback-deploy-resources-preloader/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK no html template -->
+    <!-- FALLBACK FX in Swing app -->
+    <target name="-fallback-deploy-app-nosign-nopreloader-notemplate-swing" depends="-check-fallback-nosign-deploy-swing-possible" if="nosign-nopreloader-notemplate-swing" unless="preloader-app-no-workaround">
+        <echo message="-fallback-deploy-app-nosign-nopreloader-notemplate-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-swing/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy/>
+    </target>
+
+    <!-- FALLBACK project without preloader -->
+    <!-- FALLBACK html template -->
+    <!-- FALLBACK FX in Swing app -->
+    <target name="-fallback-deploy-app-nosign-nopreloader-template-swing" depends="-check-fallback-nosign-deploy-swing-possible" if="nosign-nopreloader-template-swing" unless="preloader-app-no-workaround">
+        <echo message="-fallback-deploy-app-nosign-nopreloader-template-swing" level="verbose"/>
+        <deploy-defines/>
+        <deploy-preprocess/>
+        <fallback-deploy-application-def-swing/>
+        <fallback-deploy-resources/>
+        <fallback-deploy-jar/>
+        <fallback-deploy-deploy-template/>
+    </target>
+
+
+    <!-- Project Build Targets -->
+
+    <target name="jfx-build" depends="-jfx-do-compile, -jfx-do-jar, -jfx-do-post-jar"/>
+    <target name="jfx-build-noscript" depends="-set-fallback-no-javascript, -jfx-do-compile, -jfx-do-jar, -jfx-do-post-jar"/>
+    
+    <target name="jfx-rebuild" depends="clean, -jfx-do-compile, -jfx-do-jar, -jfx-do-post-jar"/>
+    <target name="jfx-rebuild-noscript" depends="-set-fallback-no-javascript, clean, -jfx-do-compile, -jfx-do-jar, -jfx-do-post-jar"/>
+
+    <target name="jfx-build-native" depends="-set-do-build-native-package, -check-ant-jre-supports-native-packaging, -check-native-packager-external-tools, jfx-rebuild"/>
+    <target name="jfx-build-native-noscript" depends="-set-do-build-native-package, -check-ant-jre-supports-native-packaging, -check-native-packager-external-tools, jfx-rebuild-noscript"/>
+
+    <target name="-check-do-jar">
+        <condition property="do-jar-false">
+            <and>
+                <isset property="do.jar"/>
+                <equals arg1="${do.jar}" arg2="false"/>
+            </and>
+        </condition>
+    </target>
+    <target name="-set-fallback-no-javascript">
+        <property name="fallback.no.javascript" value="true"/>
+        <echo message="Warning: Using fallback build infrastructure due to default JDK missing JavaScript support."/>
+    </target>
+    <target name="-jfx-do-compile" depends="-check-do-jar" if="do-jar-false">
+        <antcall target="compile"/>
+    </target>
+    <target name="-jfx-do-jar" depends="-check-do-jar" unless="do-jar-false">
+        <antcall target="jar"/>
+    </target>
+    <target name="-jfx-do-post-jar" depends="-init-check,-check-project" if="preloader-app">
+        <!-- Preloaders are created using SE copylibs task that creates readme file relevant for SE only -->
+        <delete file="${basedir}${file.separator}${dist.dir}${file.separator}README.TXT"/>
+    </target>
+    
+    <target name="-set-do-build-native-package">
+        <property name="do.build.native.package" value="true"/>
+        <echo message="do.build.native.package = ${do.build.native.package}" level="verbose"/>
+    </target>
+    <target name="-check-ant-jre-supports-native-packaging" depends="-check-ant-jre-version">
+        <fail message="Error:${line.separator}JavaFX native packager requires NetBeans to run on JDK 1.7u6 or later !" if="have-ant-jre-pre7u6"/>
+    </target>
+    
+    <target name="-call-pre-jfx-native" if="do.build.native.package">
+        <antcall target="-pre-jfx-native"/>
+    </target>
+    <target name="-call-post-jfx-native" if="do.build.native.package">
+        <antcall target="-post-jfx-native"/>
+    </target>
+
+    <target name="-check-native-bundling-type" depends="-check-operating-system" if="do.build.native.package">
+        <condition property="need.Inno.presence">
+            <and>
+                <isset property="running.on.windows"/>
+                <isset property="javafx.native.bundling.type"/>
+                <or>
+                    <equals arg1="${javafx.native.bundling.type}" arg2="all" casesensitive="false"/>
+                    <equals arg1="${javafx.native.bundling.type}" arg2="installer" casesensitive="false"/>
+                </or>
+            </and>
+        </condition>
+        <condition property="need.WiX.presence">
+            <and>
+                <isset property="running.on.windows"/>
+                <isset property="javafx.native.bundling.type"/>
+                <or>
+                    <equals arg1="${javafx.native.bundling.type}" arg2="all" casesensitive="false"/>
+                    <equals arg1="${javafx.native.bundling.type}" arg2="installer" casesensitive="false"/>
+                </or>
+            </and>
+        </condition>
+        <echo message="need.Inno.presence:${need.Inno.presence}" level="verbose"/>
+        <echo message="need.WiX.presence:${need.WiX.presence}" level="verbose"/>
+    </target>
+    <target name="-check-Inno-presence" depends="-check-native-bundling-type" if="need.Inno.presence">
+        <local name="exec-output"/>
+        <local name="exec-error"/>
+        <local name="exec-result"/>
+        <exec executable="iscc" outputproperty="exec-output" failifexecutionfails="false" errorproperty="exec-error" resultproperty="exec-result"/>
+        <echo message="exec-output:${exec-output}" level="verbose"/>
+        <echo message="exec-error:${exec-error}" level="verbose"/>
+        <echo message="exec-result:${exec-result}" level="verbose"/>
+        <condition property="missing.Inno">
+            <not><and>
+                <contains string="${exec-output}" substring="Inno Setup"/>
+                <not><contains string="${exec-output}" substring="Inno Setup 1"/></not>
+                <not><contains string="${exec-output}" substring="Inno Setup 2"/></not>
+                <not><contains string="${exec-output}" substring="Inno Setup 3"/></not>
+                <not><contains string="${exec-output}" substring="Inno Setup 4"/></not>
+            </and></not>
+        </condition>
+    </target>
+    <target name="-check-WiX-presence" depends="-check-native-bundling-type" if="need.WiX.presence">
+        <local name="exec-output"/>
+        <local name="exec-error"/>
+        <local name="exec-result"/>
+        <exec executable="candle" outputproperty="exec-output" failifexecutionfails="false" errorproperty="exec-error" resultproperty="exec-result">
+            <arg value="-?"/>
+        </exec>
+        <echo message="exec-output:${exec-output}" level="verbose"/>
+        <echo message="exec-error:${exec-error}" level="verbose"/>
+        <echo message="exec-result:${exec-result}" level="verbose"/>
+        <condition property="missing.WiX">
+            <not><and>
+                <contains string="${exec-output}" substring="Windows Installer Xml Compiler version"/>
+                <not><contains string="${exec-output}" substring="Windows Installer Xml Compiler version 1"/></not>
+                <not><contains string="${exec-output}" substring="Windows Installer Xml Compiler version 2"/></not>
+            </and></not>
+        </condition>
+    </target>
+    <target name="-check-native-packager-external-tools" depends="-check-Inno-presence, -check-WiX-presence">
+        <property name="missing.Inno.message" value="JavaFX native packager requires external Inno Setup 5+ tools installed and included on PATH. See http://www.jrsoftware.org/"/>
+        <property name="missing.WiX.message" value="JavaFX native packager requires external WiX 3.0+ tools installed and included on PATH. See http://wix.sourceforge.net/"/>
+        <condition property="missing.Inno.WiX">
+            <and>
+                <isset property="missing.Inno"/>
+                <isset property="missing.WiX"/>
+            </and>
+        </condition>
+        <fail message="Error:${line.separator}${missing.Inno.message}${line.separator}${missing.WiX.message}" if="missing.Inno.WiX"/>
+        <fail message="Error:${line.separator}${missing.Inno.message}" if="missing.Inno"/>
+        <fail message="Error:${line.separator}${missing.WiX.message}" if="missing.WiX"/>
+    </target>
+
+    <!-- Project Run Support -->
+
+    <target name="-warn-of-preloader" depends="-check-project" if="preloader-app-no-workaround">
+        <fail message="Error:${line.separator}JavaFX 2 Preloader Project can not be executed directly.${line.separator}Please execute instead a JavaFX Application that uses the Preloader."/>
+    </target>
+    
+    <target name="-mark-project-state-running">
+        <property name="project.state.running" value="true"/>
+        <echo message="project.state.running = ${project.state.running}" level="verbose"/>
+    </target>
+    <target name="-mark-project-state-debugging">
+        <property name="project.state.debugging" value="true"/>
+        <echo message="project.state.debugging = ${project.state.debugging}" level="verbose"/>
+    </target>
+    <target name="-mark-project-state-profiling">
+        <property name="project.state.profiling" value="true"/>
+        <echo message="project.state.profiling = ${project.state.profiling}" level="verbose"/>
+    </target>
+    <target name="-mark-project-needs-jnlp">
+        <property name="project.needs.jnlp" value="true"/>
+        <echo message="project.needs.jnlp = ${project.needs.jnlp}" level="verbose"/>
+    </target>
+    
+    <!-- set property javafx.disable.concurrent.runs=true to disable runs from temporary directory -->
+    <target name="-check-concurrent-runs">
+        <condition property="disable-concurrent-runs">
+            <and>
+                <isset property="javafx.disable.concurrent.runs"/>
+                <equals arg1="${javafx.disable.concurrent.runs}" arg2="true" trim="true"/>
+            </and>
+        </condition>
+        <condition property="temp.run.jar" value="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}">
+            <isset property="disable-concurrent-runs"/>
+        </condition>
+        <condition property="temp.run.jnlp" value="${jfx.deployment.jnlp}">
+            <isset property="disable-concurrent-runs"/>
+        </condition>
+        <condition property="temp.run.html" value="${jfx.deployment.html}">
+            <isset property="disable-concurrent-runs"/>
+        </condition>
+    </target>
+    <target name="-create-temp-run-dir" depends="-check-concurrent-runs" unless="disable-concurrent-runs">
+        <echo message="Creating temp run dir" level="verbose"/>
+        <tempfile property="temp.run.dir" destDir="${basedir}${file.separator}${dist.dir}${file.separator}" prefix="run"/>
+        <echo message="temp.run.dir = ${temp.run.dir}" level="verbose"/>
+        <copy todir="${temp.run.dir}" includeemptydirs="true" overwrite="true">
+            <fileset dir="${basedir}${file.separator}${dist.dir}">
+                <exclude name="**${file.separator}bundles${file.separator}**"/>
+                <exclude name="**${file.separator}run*${file.separator}**"/>
+            </fileset>
+        </copy>        
+        <property name="temp.run.jar" value="${temp.run.dir}${file.separator}${jfx.deployment.jar}"/>
+        <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
+        <property name="temp.run.jnlp" value="${temp.run.dir}${file.separator}${jfx.deployment.base}.jnlp"/>
+        <property name="temp.run.html" value="${temp.run.dir}${file.separator}${jfx.deployment.base}.html"/>
+    </target>
+    <target name="-remove-temp-run-dir" if="temp.run.dir">
+        <echo message="Removing temp run dir" level="verbose"/>
+        <delete dir="${temp.run.dir}" quiet="true" failonerror="false"/>
+    </target>
+    <target depends="init,compile,jar,-create-temp-run-dir" description="Run JavaFX project standalone." name="jfx-project-run">
+        <echo message="Executing ${main.class} from ${temp.run.jar} using platform ${platform.java}"/>
+        <property name="run.jvmargs" value=""/>
+        <property name="run.jvmargs.ide" value=""/>        
+        <java classname="${main.class}" dir="${work.dir}" fork="true" jvm="${platform.java}">
+            <jvmarg line="${endorsed.classpath.cmd.line.arg}"/>
+            <jvmarg value="-Dfile.encoding=${runtime.encoding}"/>
+            <redirector errorencoding="${runtime.encoding}" inputencoding="${runtime.encoding}" outputencoding="${runtime.encoding}"/>
+            <jvmarg line="${run.jvmargs}"/>
+            <jvmarg line="${run.jvmargs.ide}"/>
+            <classpath>
+                <path path="${temp.run.jar}:${javac.classpath}"/>
+            </classpath>
+            <arg line="${application.args}"/>
+            <syspropertyset>
+                <propertyref prefix="run-sys-prop."/>
+                <mapper from="run-sys-prop.*" to="*" type="glob"/>
+            </syspropertyset>
+        </java>
+        <antcall target="-remove-temp-run-dir"/>
+    </target>
+
+
+    <!-- Running/Debugging/Profiling Standalone -->
+
+    <target name="jfxsa-run" depends="-mark-project-state-running,-clean-if-config-changed,-check-jfx-runtime,-warn-of-preloader,jfx-project-run"/>
+    <target name="jfxsa-run-noscript" depends="-set-fallback-no-javascript, jfxsa-run"/>
+
+    <target name="jfxsa-debug" depends="-mark-project-state-debugging,-clean-if-config-changed,jar,-check-jfx-runtime,-warn-of-preloader,debug"/>
+    <target name="jfxsa-debug-noscript" depends="-set-fallback-no-javascript, jfxsa-debug"/>
+    
+    <target name="jfxsa-profile" depends="-mark-project-state-profiling,-check-jfx-runtime,-warn-of-preloader,profile"/>
+    <target name="jfxsa-profile-noscript" depends="-set-fallback-no-javascript, jfxsa-profile"/>
+
+    <target name="-check-clean-if-config-changed" depends="-init-project">
+        <deploy-defines/>
+        <uptodate property="jfx.deployment.jar.newer.than.nbproject" targetfile="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}" >
+            <srcfiles dir="${basedir}${file.separator}nbproject" includes="**${file.separator}*"/>
+        </uptodate>
+        <echo message="jfx.deployment.jar.newer.than.nbproject = ${jfx.deployment.jar.newer.than.nbproject}" level="verbose"/>
+        <available file="${jfx.deployment.dir}${file.separator}${jfx.deployment.jar}" type="file" property="jfx.deployment.jar.exists"/>
+        <condition property="request.clean.due.to.config.change">
+            <and>
+                <isset property="jfx.deployment.jar.exists"/>
+                <not><isset property="jfx.deployment.jar.newer.than.nbproject"/></not>
+            </and>
+        </condition>
+    </target>
+    <target name="-clean-if-config-changed" depends="-check-clean-if-config-changed" if="request.clean.due.to.config.change">
+        <echo message="Config change detected. Invoking clean." level="verbose"/>
+        <antcall target="clean"/>
+    </target>
+
+
+    <!-- Shared Debugging init -->
+
+    <target name="-init-debug-args">
+        <property name="version-output" value="java version &quot;${ant.java.version}"/>
+        <condition property="have-jdk-older-than-1.4">
+            <or>
+                <contains string="${version-output}" substring="java version &quot;1.0"/>
+                <contains string="${version-output}" substring="java version &quot;1.1"/>
+                <contains string="${version-output}" substring="java version &quot;1.2"/>
+                <contains string="${version-output}" substring="java version &quot;1.3"/>
+            </or>
+        </condition>
+        <condition else="-Xdebug" property="debug-args-line" value="-Xdebug -Xnoagent -Djava.compiler=none">
+            <istrue value="${have-jdk-older-than-1.4}"/>
+        </condition>
+        <condition else="dt_socket" property="debug-transport-by-os" value="dt_shmem">
+            <os family="windows"/>
+        </condition>
+        <condition else="${debug-transport-by-os}" property="debug-transport" value="${debug.transport}">
+            <isset property="debug.transport"/>
+        </condition>
+    </target>
+
+
+    <!-- Running/Debugging/Profiling as WebStart -->
+    
+    <target name="-check-jnlp-file-fx" depends="-swing-api-check" unless="fx-in-swing-app-workaround">
+        <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
+        <property name="jfx.deployment.jnlp" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}.jnlp"/>
+    </target>
+    <target name="-check-jnlp-file-swing" depends="-swing-api-check" if="fx-in-swing-app-workaround">
+        <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
+        <property name="jfx.deployment.jnlp" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}_application.jnlp"/>
+    </target>
+    <target name="-check-jnlp-file" depends="-check-jnlp-file-fx,-check-jnlp-file-swing">
+        <condition property="jnlp-file-exists">
+            <available file="${jfx.deployment.jnlp}"/>
+        </condition>
+        <condition property="jnlp-file-exists+netbeans.home">
+            <and>
+                <isset property="jnlp-file-exists"/>
+                <isset property="netbeans.home"/>
+            </and>
+        </condition>
+    </target>
+
+    <target name="-resolve-jnlp-file" depends="-check-jnlp-file" unless="jnlp-file-exists">
+        <antcall target="jfx-deployment"/>
+        <antcall target="-check-jnlp-file"/>
+    </target>
+
+    <!-- set property javafx.enable.concurrent.external.runs=true to enable multiple runs of the same WebStart or Run-in-Browser project -->
+    <target name="-check-concurrent-jnlp-runs" depends="-resolve-jnlp-file">
+        <condition property="disable-concurrent-runs">
+            <not>
+                <and>
+                    <isset property="javafx.enable.concurrent.external.runs"/>
+                    <equals arg1="${javafx.enable.concurrent.external.runs}" arg2="true" trim="true"/>
+                </and>
+            </not>
+        </condition>
+        <condition property="temp.run.jnlp" value="${jfx.deployment.jnlp}">
+            <isset property="disable-concurrent-runs"/>
+        </condition>
+    </target>
+    <target name="-warn-concurrent-jnlp-runs" unless="disable-concurrent-runs">
+        <echo message="Note: Concurrent Run as WebStart enabled.${line.separator}Temporary directory ${temp.run.dir}${line.separator}will remain unused when WebStart execution has finished. Use project Clean to delete unused directories."/>
+    </target>
+
+    <target name="jfxws-run" if="jnlp-file-exists" depends="-mark-project-state-running,-clean-if-config-changed,-mark-project-needs-jnlp,-check-jdk-7u4or5-mac,jar,
+            -check-jfx-webstart,-resolve-jnlp-file,-check-jfx-runtime,-check-concurrent-jnlp-runs,-create-temp-run-dir" 
+            description="Start JavaFX javaws execution">
+        <echo message="Executing ${temp.run.jnlp} using ${active.webstart.executable}"/>
+        <exec executable="${active.webstart.executable}">
+            <arg file="${temp.run.jnlp}"/>
+        </exec>
+        <antcall target="-warn-concurrent-jnlp-runs"/>
+    </target>
+    
+    <target name="jfxws-debug" if="jnlp-file-exists+netbeans.home" depends="-mark-project-state-debugging,-clean-if-config-changed,-mark-project-needs-jnlp,
+            -check-jdk-7u4or5-mac,jar,-check-jfx-webstart,-resolve-jnlp-file,-check-jfx-runtime,
+            -debug-start-debugger,-debug-javaws-debuggee" description="Debug JavaFX javaws project in IDE"/>
+        
+    <target name="-debug-javaws-debuggee" depends="-init-debug-args">
+        <echo message="Executing ${jfx.deployment.jnlp} in debug mode using ${active.webstart.executable}"/>
+        <exec executable="${active.webstart.executable}">
+            <env key="JAVAWS_VM_ARGS" value="${debug-args-line} -Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+            <arg value="-wait"/>
+            <arg file="${jfx.deployment.jnlp}"/>
+        </exec>
+    </target>
+    
+    <target name="-profile-check-1">
+        <property name="run.jvmargs.ide" value=""/>        
+        <condition property="profiler.configured">
+            <or>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-agentpath:"/>
+                <contains casesensitive="true" string="${run.jvmargs.ide}" substring="-javaagent:"/>
+            </or>
+        </condition>
+    </target>
+    
+    <target if="jnlp-file-exists+netbeans.home" name="-profile-check-jnlp">
+        <antcall target="-profile-check-1"/>
+    </target>
+    
+    <target name="-do-jfxws-profile" depends="-mark-project-state-profiling,-mark-project-needs-jnlp,
+            -check-jdk-7u4or5-mac,jar,-check-jfx-webstart,-resolve-jnlp-file,-check-jfx-runtime">
+        <echo message="Executing ${jfx.deployment.jnlp} in profile mode using ${active.webstart.executable}"/>
+        <property name="run.jvmargs.ide" value=""/>        
+        <exec executable="${active.webstart.executable}">
+            <env key="JAVAWS_VM_ARGS" value="${run.jvmargs.ide}"/>
+            <arg value="-wait"/>
+            <arg file="${jfx.deployment.jnlp}"/>
+        </exec>
+    </target>
+    
+    <target name="jfxws-profile" if="profiler.configured" 
+        depends="-profile-check-1"
+        description="Profile JavaFX javaws project in IDE">
+        <startprofiler/>
+        <antcall target="-do-jfxws-profile"/>
+    </target>
+    
+    <target name="jfxws-run-noscript" depends="-set-fallback-no-javascript, jfxws-run"/>
+
+    <target name="jfxws-debug-noscript" depends="-set-fallback-no-javascript, jfxws-debug"/>
+
+    <target name="jfxws-profile-noscript" depends="-set-fallback-no-javascript, jfxws-profile"/>
+
+
+    <!-- Running/Debugging/Profiling in Browser -->
+
+    <target name="-check-selected-browser-path" depends="-check-default-run-config">
+        <condition property="javafx.run.inbrowser.undefined">
+            <or>
+                <and>
+                    <isset property="javafx.run.inbrowser"/>
+                    <equals arg1="${javafx.run.inbrowser}" arg2="undefined"/>
+                </and>
+                <and>
+                    <isset property="javafx.run.inbrowser.path"/>
+                    <equals arg1="${javafx.run.inbrowser.path}" arg2="undefined"/>
+                </and>
+            </or>
+        </condition>
+        <condition property="javafx.run.inbrowser.path-exists">
+            <and>
+                <isset property="javafx.run.inbrowser.path"/>
+                <available file="${javafx.run.inbrowser.path}"/>
+            </and>
+        </condition>
+        <fail message="Error:${line.separator}Browser selection not recognizable from ${config} run configuration.${line.separator}Please go to Project Properties dialog, category Run, to select a valid browser." unless="javafx.run.inbrowser.path"/>
+        <fail message="Error:${line.separator}No browser defined in ${config} run configuration.${line.separator}Please verify in Tools->Options dialog that NetBeans recognizes a valid browser, then go to Project Properties dialog, category Run, to select a valid browser." if="javafx.run.inbrowser.undefined"/>
+        <fail message="Error:${line.separator}Browser ${javafx.run.inbrowser.path} referred from ${config} run configuration can not be found.${line.separator}(This can happen, e.g, when the JavaFX Project is transferred to another system.)${line.separator}Please go to Project Properties dialog, category Run, to select a valid browser." unless="javafx.run.inbrowser.path-exists"/>
+    </target>
+
+    <target name="-substitute-template-processed-html-file" depends="-check-project" if="html-template-available">
+        <deploy-process-template/>
+    </target>
+    <target name="-check-template-processed-html-file" depends="-substitute-template-processed-html-file">
+        <condition property="html-file-exists">
+            <and>
+                <isset property="html-template-available"/>
+                <available file="${javafx.run.htmltemplate.processed}"/>
+            </and>
+        </condition>
+    </target>
+    
+    <target name="-set-template-processed-html-file" depends="-check-template-processed-html-file" if="html-file-exists">
+        <property name="jfx.deployment.html" location="${javafx.run.htmltemplate.processed}"/>
+    </target>
+    
+    <target name="-set-html-file" depends="-set-template-processed-html-file" unless="html-file-exists">
+        <basename property="jfx.deployment.base" file="${jfx.deployment.jar}" suffix=".jar"/>
+        <property name="jfx.deployment.html" location="${jfx.deployment.dir}${file.separator}${jfx.deployment.base}.html"/>
+        <condition property="html-file-exists">
+            <available file="${jfx.deployment.html}"/>
+        </condition>
+        <condition property="html-file-exists+netbeans.home">
+            <and>
+                <isset property="html-file-exists"/>
+                <isset property="netbeans.home"/>
+            </and>
+        </condition>
+    </target>
+
+    <!-- set property javafx.enable.concurrent.external.runs=true to enable multiple runs of the same WebStart or Run-in-Browser project -->
+    <target name="-check-concurrent-html-runs" depends="-set-html-file">
+        <condition property="disable-concurrent-runs">
+            <or>
+                <not>
+                    <and>
+                        <isset property="javafx.enable.concurrent.external.runs"/>
+                        <equals arg1="${javafx.enable.concurrent.external.runs}" arg2="true" trim="true"/>
+                    </and>
+                </not>
+                <and>
+                    <isset property="html-template-available"/>
+                    <available file="${javafx.run.htmltemplate.processed}"/>
+                </and>
+            </or>
+        </condition>
+        <condition property="temp.run.html" value="${jfx.deployment.html}">
+            <isset property="disable-concurrent-runs"/>
+        </condition>
+    </target>
+    <target name="-warn-concurrent-html-runs" unless="disable-concurrent-runs">
+        <echo message="Note: Concurrent Run in Browser enabled.${line.separator}Temporary directory ${temp.run.dir}${line.separator}will remain unused when execution in browser has finished. Use project Clean to delete unused directories."/>
+    </target>
+
+    <target name="jfxbe-run" if="html-file-exists" depends="-mark-project-state-running,-clean-if-config-changed,-mark-project-needs-jnlp,-check-jdk-7u4or5-mac,jar,
+            -check-selected-browser-path,-set-html-file,-check-jfx-runtime,-check-concurrent-html-runs,-create-temp-run-dir"
+            description="Start JavaFX execution in browser">
+        <echo message="Executing ${temp.run.html} using ${javafx.run.inbrowser}"/>
+        <echo message="(${javafx.run.inbrowser.path})"/>
+        <exec executable="${javafx.run.inbrowser.path}">
+            <arg file="${temp.run.html}"/>
+        </exec>
+        <antcall target="-warn-concurrent-html-runs"/>
+    </target>
+    
+    <target name="jfxbe-debug" if="html-file-exists+netbeans.home" depends="-mark-project-state-debugging,-clean-if-config-changed,-mark-project-needs-jnlp,
+            -check-jdk-7u4or5-mac,jar,-check-selected-browser-path,-set-html-file,-check-jfx-runtime,
+            -debug-start-debugger,-debug-jfxbe-debuggee" description="Debug JavaFX project in browser"/>
+        
+    <target name="-debug-jfxbe-debuggee" depends="-init-debug-args">
+        <echo message="Executing ${jfx.deployment.html} in debug mode using ${javafx.run.inbrowser}"/>
+        <echo message="(${javafx.run.inbrowser.path})"/>
+        <exec executable="${javafx.run.inbrowser.path}">
+            <env key="_JPI_VM_OPTIONS" value="${debug-args-line} -Xrunjdwp:transport=${debug-transport},address=${jpda.address}"/>
+            <arg file="${jfx.deployment.html}"/>
+        </exec>
+    </target>
+
+    <target if="html-file-exists+netbeans.home" name="-profile-check-html">
+        <antcall target="-profile-check-1"/>
+    </target>
+
+    <target name="-do-jfxbe-profile" depends="-mark-project-state-profiling,-mark-project-needs-jnlp,
+            -check-jdk-7u4or5-mac,jar,-check-selected-browser-path,-set-html-file,-check-jfx-runtime">
+        <echo message="Executing ${jfx.deployment.html} in profile mode using ${javafx.run.inbrowser}"/>
+        <echo message="(${javafx.run.inbrowser.path})"/>
+        <property name="run.jvmargs.ide" value=""/>        
+        <exec executable="${javafx.run.inbrowser.path}">
+            <env key="_JPI_VM_OPTIONS" value="${run.jvmargs.ide}"/>
+            <arg file="${jfx.deployment.html}"/>
+        </exec>
+    </target>
+
+    <target name="jfxbe-profile" if="profiler.configured"
+        depends="-profile-check-html"
+        description="Profile JavaFX project in browser">
+        <startprofiler/>
+        <antcall target="-do-jfxbe-profile"/>
+    </target>
+
+    <target name="jfxbe-run-noscript" depends="-set-fallback-no-javascript, jfxbe-run"/>
+
+    <target name="jfxbe-debug-noscript" depends="-set-fallback-no-javascript, jfxbe-debug"/>
+
+    <target name="jfxbe-profile-noscript" depends="-set-fallback-no-javascript, jfxbe-profile"/>
+
+
+</project>
diff --git a/DuskZ/nbproject/project.properties b/DuskZ/nbproject/project.properties
new file mode 100644 (file)
index 0000000..0c0a31d
--- /dev/null
@@ -0,0 +1,120 @@
+project.license=dusk3
+annotation.processing.enabled=true
+annotation.processing.enabled.in.editor=false
+annotation.processing.processors.list=
+annotation.processing.run.all.processors=true
+annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output
+application.title=DuskZ
+application.vendor=notzed
+build.classes.dir=${build.dir}/classes
+build.classes.excludes=**/*.java,**/*.form
+# This directory is removed when the project is cleaned:
+build.dir=build
+build.generated.dir=${build.dir}/generated
+build.generated.sources.dir=${build.dir}/generated-sources
+# Only compile against the classpath explicitly listed here:
+build.sysclasspath=ignore
+build.test.classes.dir=${build.dir}/test/classes
+build.test.results.dir=${build.dir}/test/results
+compile.on.save=true
+compile.on.save.unsupported.javafx=true
+# Uncomment to specify the preferred debugger connection transport:
+#debug.transport=dt_socket
+debug.classpath=\
+    ${run.classpath}
+debug.test.classpath=\
+    ${run.test.classpath}
+# This directory is removed when the project is cleaned:
+dist.dir=dist
+dist.jar=${dist.dir}/DuskZ.jar
+dist.javadoc.dir=${dist.dir}/javadoc
+endorsed.classpath=
+excludes=
+includes=**
+# Non-JavaFX jar file creation is deactivated in JavaFX 2.0+ projects
+jar.archive.disabled=true
+jar.compress=false
+javac.classpath=\
+    ${javafx.runtime}/lib/jfxrt.jar:\
+    ${javafx.runtime}/lib/deploy.jar:\
+    ${javafx.runtime}/lib/javaws.jar:\
+    ${javafx.runtime}/lib/plugin.jar:\
+    ${reference.DuskCommon.jar}
+# Space-separated list of extra javac options
+javac.compilerargs=
+javac.deprecation=false
+javac.processorpath=\
+    ${javac.classpath}
+javac.source=1.7
+javac.target=1.7
+javac.test.classpath=\
+    ${javac.classpath}:\
+    ${build.classes.dir}
+javac.test.processorpath=\
+    ${javac.test.classpath}
+javadoc.additionalparam=
+javadoc.author=false
+javadoc.encoding=${source.encoding}
+javadoc.noindex=false
+javadoc.nonavbar=false
+javadoc.notree=false
+javadoc.private=false
+javadoc.splitindex=true
+javadoc.use=true
+javadoc.version=false
+javadoc.windowtitle=
+javafx.binarycss=false
+javafx.deploy.adddesktopshortcut=false
+javafx.deploy.addstartmenushortcut=false
+javafx.deploy.allowoffline=true
+# If true, application update mode is set to 'background', if false, update mode is set to 'eager'
+javafx.deploy.backgroundupdate=false
+javafx.deploy.embedJNLP=true
+javafx.deploy.includeDT=true
+javafx.deploy.installpermanently=false
+javafx.deploy.permissionselevated=false
+# Set true to prevent creation of temporary copy of deployment artifacts before each run (disables concurrent runs)
+javafx.disable.concurrent.runs=false
+# Set true to enable multiple concurrent runs of the same WebStart or Run-in-Browser project
+javafx.enable.concurrent.external.runs=false
+# This is a JavaFX project
+javafx.enabled=true
+javafx.fallback.class=com.javafx.main.NoJavaFXFallback
+# Main class for JavaFX
+javafx.main.class=duskz.client.fx.DuskFX
+javafx.native.bundling.enabled=false
+javafx.native.bundling.type=none
+javafx.preloader.class=
+# This project does not use Preloader
+javafx.preloader.enabled=false
+javafx.preloader.jar.filename=
+javafx.preloader.jar.path=
+javafx.preloader.project.path=
+javafx.preloader.type=none
+# Set true for GlassFish only. Rebases manifest classpaths of JARs in lib dir. Not usable with signed JARs.
+javafx.rebase.libs=false
+javafx.run.height=600
+javafx.run.width=800
+javafx.runtime=${platforms.Default_JavaFX_Platform.javafx.runtime.home}
+javafx.sdk=${platforms.Default_JavaFX_Platform.javafx.sdk.home}
+javafx.signing.enabled=false
+javafx.signing.type=notsigned
+# Pre-JavaFX 2.0 WebStart is deactivated in JavaFX 2.0+ projects
+jnlp.enabled=false
+# Main class for Java launcher
+main.class=com.javafx.main.Main
+manifest.file=manifest.mf
+meta.inf.dir=${src.dir}/META-INF
+mkdist.disabled=false
+platform.active=Default_JavaFX_Platform
+project.DuskCommon=../DuskCommon
+reference.DuskCommon.jar=${project.DuskCommon}/dist/DuskCommon.jar
+run.classpath=\
+    ${dist.jar}:\
+    ${javac.classpath}
+run.test.classpath=\
+    ${javac.test.classpath}:\
+    ${build.test.classes.dir}
+source.encoding=UTF-8
+src.dir=src
+test.src.dir=test
diff --git a/DuskZ/nbproject/project.xml b/DuskZ/nbproject/project.xml
new file mode 100644 (file)
index 0000000..7782e6a
--- /dev/null
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.java.j2seproject</type>
+    <configuration>
+        <buildExtensions xmlns="http://www.netbeans.org/ns/ant-build-extender/1">
+            <extension file="jfx-impl.xml" id="jfx">
+                <dependency dependsOn="-check-javafx" target="-init-check"/>
+                <dependency dependsOn="-jfx-copylibs" target="-post-jar"/>
+                <dependency dependsOn="-rebase-libs" target="-post-jar"/>
+                <dependency dependsOn="jfx-deployment" target="-post-jar"/>
+                <dependency dependsOn="jar" target="debug"/>
+                <dependency dependsOn="-jfx-copylibs" target="jar"/>
+                <dependency dependsOn="-rebase-libs" target="jar"/>
+                <dependency dependsOn="jar" target="profile"/>
+                <dependency dependsOn="jar" target="run"/>
+            </extension>
+        </buildExtensions>
+        <data xmlns="http://www.netbeans.org/ns/j2se-project/3">
+            <name>DuskZ</name>
+            <explicit-platform explicit-source-supported="true"/>
+            <source-roots>
+                <root id="src.dir"/>
+            </source-roots>
+            <test-roots>
+                <root id="test.src.dir"/>
+            </test-roots>
+        </data>
+        <references xmlns="http://www.netbeans.org/ns/ant-project-references/1">
+            <reference>
+                <foreign-project>DuskCommon</foreign-project>
+                <artifact-type>jar</artifact-type>
+                <script>build.xml</script>
+                <target>jar</target>
+                <clean-target>clean</clean-target>
+                <id>jar</id>
+            </reference>
+        </references>
+    </configuration>
+</project>
diff --git a/DuskZ/src/duskz/client/Bookmarks.java b/DuskZ/src/duskz/client/Bookmarks.java
new file mode 100644 (file)
index 0000000..36e54f6
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Bookmark format is host:port
+ *
+ * TODO: store username too?
+ *
+ * @author notzed
+ */
+public class Bookmarks {
+
+       List<Bookmark> bookmarks = new ArrayList<>();
+
+       public List<Bookmark> getBookmarks() {
+               return bookmarks;
+       }
+
+       public void setBookmarks(List<Bookmark> bookmarks) {
+               this.bookmarks = bookmarks;
+       }
+
+       public Bookmarks() {
+       }
+
+       public void load(String path) throws IOException {
+               try (BufferedReader br = Files.newBufferedReader(Paths.get(path), Charset.forName("UTF-8"))) {
+                       String l;
+
+                       while ((l = br.readLine()) != null) {
+                               try {
+                                       bookmarks.add(Bookmark.valueOf(l));
+                               } catch (NumberFormatException ex) {
+                               }
+                       }
+               } catch (NoSuchFileException x) {
+                       // ignore it
+               }
+       }
+
+       public void save(String path) throws IOException {
+               try (BufferedWriter br = Files.newBufferedWriter(Paths.get(path), Charset.forName("UTF-8"), StandardOpenOption.CREATE,
+                               StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
+                       for (Bookmark b : bookmarks) {
+                               b.write(br);
+                       }
+               }
+       }
+
+       public static class Bookmark {
+
+               public String host;
+               public int port;
+
+               public Bookmark(String host, int port) {
+                       this.host = host;
+                       this.port = port;
+               }
+
+               public static Bookmark valueOf(String v) {
+                       int p = v.indexOf(':');
+                       if (p != -1) {
+                               return new Bookmark(v.substring(0, p), Integer.valueOf(v.substring(p + 1)));
+                       } else {
+                               return new Bookmark(v, 7400);
+                       }
+               }
+
+               private void write(BufferedWriter br) throws IOException {
+                       br.write(host);
+                       br.write(':');
+                       br.write(Integer.toString(port));
+                       br.write('\n');
+               }
+
+               @Override
+               public String toString() {
+                       return host + ":" + port;
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/ClientMap.java b/DuskZ/src/duskz/client/ClientMap.java
new file mode 100644 (file)
index 0000000..b39a324
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map.Entry;
+
+/**
+ * Client map has a fixed set of tiles for the background. And then a bunch of
+ * entities roaming across it.
+ *
+ * I experimented here with a different implementation to the server map in that
+ * the entities by location uses a hash table rather than an array. This allows
+ * me to reference them by absolute coordinates which simplifies a lot of the
+ * code.
+ *
+ * @author notzed
+ */
+public class ClientMap {
+
+       /**
+        * Offset of map (top-left corner)
+        */
+       public int offx, offy;
+       /**
+        * Tile indices for images
+        */
+       private short[] tiles;
+       /**
+        * Entities by id
+        */
+       private HashMap<Long, Entity> entityByID = new HashMap<>();
+       /**
+        * Entities by name
+        * TODO: If names do not need unique 'numbers' then this
+        * index can be completely removed.
+        */
+       private HashMap<String, List<Entity>> entityByName = new HashMap<>();
+       /**
+        * Enities by location. Location is encoded as ( y << 16) | x
+        */
+       private HashMap<Integer, List<Entity>> entityByLocation = new HashMap<>();
+       /**
+        * Width of map shown
+        */
+       public final int cols;
+       /**
+        * Height of map shown
+        */
+       public final int rows;
+
+       public ClientMap(int cols, int rows) {
+               this.cols = cols;
+               this.rows = rows;
+
+               tiles = new short[cols * rows];
+       }
+
+       public Collection<Entity> getEntities() {
+               return entityByID.values();
+       }
+
+       public Collection<Entity> getEntities(int x, int y) {
+               return entityByLocation.get(locationKey(x, y));
+       }
+
+       public int getTile(int x, int y) {
+               return tiles[x + y * cols];
+       }
+
+       public void setTile(int x, int y, int tile) {
+               tiles[x + y * cols] = (short) tile;
+       }
+
+       private Integer locationKey(int x, int y) {
+               return (y << 16) | x;
+       }
+
+       private Integer locationKey(Entity e) {
+               return (e.locy << 16) | e.locx;
+       }
+
+       public int mapToLocalX(int x) {
+               return x - offx;
+       }
+
+       public int mapToLocalY(int y) {
+               return y - offy;
+       }
+
+       private void addLocation(Entity e) {
+               // Index by absolute location.
+               Integer loc = locationKey(e);
+               List<Entity> bypos = entityByLocation.get(loc);
+               if (bypos == null) {
+                       bypos = new ArrayList<>();
+                       entityByLocation.put(loc, bypos);
+               }
+               bypos.add(e);
+       }
+
+       private void removeLocation(Entity e) {
+               Integer loc = locationKey(e);
+               List<Entity> bypos = entityByLocation.get(loc);
+
+               if (bypos == null || !bypos.remove(e))
+                       throw new RuntimeException("Entity not in location index");
+
+               if (bypos.isEmpty())
+                       entityByLocation.remove(loc);
+       }
+
+       public synchronized void addEntity(Entity e) {
+               if (entityByID.containsKey(e.ID)) {
+                       throw new RuntimeException("entity already in table " + e.ID + " " + e.strName);
+               }
+
+               entityByID.put(e.ID, e);
+
+               // Add byname index, and re-number if required
+               List<Entity> byname = entityByName.get(e.getSimpleName());
+               if (byname == null) {
+                       byname = new ArrayList<>();
+                       entityByName.put(e.getSimpleName(), byname);
+               }
+               byname.add(e);
+               //for (int i = 0; i < byname.size(); i++)
+               //      byname.get(i).intNum = i;
+
+               addLocation(e);
+       }
+
+       public synchronized void moveEntity(Entity e, int tox, int toy) {
+               removeLocation(e);
+               e.locx = tox;
+               e.locy = toy;
+               addLocation(e);
+       }
+
+       public synchronized void removeEntity(Entity e) {
+               removeEntity(e.ID);
+       }
+
+       public synchronized void removeEntity(long id) {
+               Entity e = entityByID.remove(id);
+
+               if (e == null) {
+                       System.out.println("removeEntity: no such entity " + id);
+                       return;
+               }
+
+               List<Entity> byname = entityByName.get(e.getSimpleName());
+               byname.remove(e);
+               if (byname.isEmpty()) {
+                       entityByName.remove(e.getSimpleName());
+               } else {
+                       //for (int i = 0; i < byname.size(); i++)
+                       //      byname.get(i).intNum = i;
+               }
+
+               removeLocation(e);
+       }
+
+       public synchronized Entity getEntity(long id) {
+               return entityByID.get(id);
+       }
+
+       boolean inside(int x, int y) {
+               int lx = x - offx;
+               int ly = y - offy;
+
+               return lx >= 0 && lx < cols
+                               && ly >= 0 && ly < rows;
+       }
+
+       public synchronized void updateTiles(int offx, int offy, DataInputStream instream) throws IOException {
+               //for (int x = 0; x < cols; x++) {
+               //      for (int y = 0; y < rows; y++) {
+               //              setTile(x, y, Short.parseShort(instream.readLine()));
+               //      }
+               //}
+               int length = instream.readInt();
+               if (length != cols * rows) {
+                       throw new IOException("Protocol error incorrect map size");
+               }
+               for (int y = 0; y < rows; y++) {
+                       for (int x = 0; x < cols; x++) {
+                               setTile(x, y, instream.readShort());
+                       }
+               }
+
+               this.offx = offx;
+               this.offy = offy;
+
+               // Prune out of range thingies
+               List<Entity> removing = new ArrayList<>();
+               for (Entry<Integer, List<Entity>> es : entityByLocation.entrySet()) {
+                       int ex = es.getKey() & 0xffff;
+                       int ey = (es.getKey() >> 16) & 0xffff;
+
+                       System.out.printf("check inside %d,%d = %s\n", ex, ey, inside(ex, ey));
+
+                       if (!inside(ex, ey)) {
+                               removing.addAll(es.getValue());
+                       }
+               }
+
+               // TODO: this could be optimised
+               // TODO: does the server need to know this
+               if (!removing.isEmpty()) {
+                       System.out.println("offset: " + this.offx + "," + this.offy);
+                       for (Entity e : removing) {
+                               System.out.println("removing out of range :" + e);
+                               removeEntity(e);
+                       }
+               }
+       }
+
+       public synchronized void updateTiles(int offx, int offy, short[] tiles) throws IOException {
+               //for (int x = 0; x < cols; x++) {
+               //      for (int y = 0; y < rows; y++) {
+               //              setTile(x, y, Short.parseShort(instream.readLine()));
+               //      }
+               //}
+               if (tiles.length != rows * cols) {
+                       throw new IOException("Protocol error incorrect map size");
+               }
+               System.arraycopy(tiles, 0, this.tiles, 0, tiles.length);
+
+               this.offx = offx;
+               this.offy = offy;
+
+               // Prune out of range thingies
+               List<Entity> removing = new ArrayList<>();
+               for (Entry<Integer, List<Entity>> es : entityByLocation.entrySet()) {
+                       int ex = es.getKey() & 0xffff;
+                       int ey = (es.getKey() >> 16) & 0xffff;
+
+                       System.out.printf("check inside %d,%d = %s\n", ex, ey, inside(ex, ey));
+
+                       if (!inside(ex, ey)) {
+                               removing.addAll(es.getValue());
+                       }
+               }
+
+               // TODO: this could be optimised
+               // TODO: does the server need to know this
+               if (!removing.isEmpty()) {
+                       System.out.println("offset: " + this.offx + "," + this.offy);
+                       for (Entity e : removing) {
+                               System.out.println("removing out of range :" + e);
+                               removeEntity(e);
+                       }
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/DataManager.java b/DuskZ/src/duskz/client/DataManager.java
new file mode 100644 (file)
index 0000000..52a0249
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client;
+
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.jar.Attributes;
+import java.util.jar.JarEntry;
+import java.util.jar.JarInputStream;
+import java.util.jar.Manifest;
+
+/**
+ * Utility for loading game objects from jar file
+ * and managing them
+ *
+ * TODO: i couldn't work out how to do generics with the inner class thing
+ *
+ * @author notzed
+ */
+public class DataManager {
+
+       String source;
+       protected ImageSet[] tilesets;
+
+       public DataManager(String source) {
+               this.source = source;
+       }
+
+       public void open() throws IOException {
+               tilesets = getImageSet("tilesets");
+               // TODO: sprites, etc.
+
+               for (ImageSet is : tilesets)
+                       is.load();
+       }
+
+       private int getInt(Attributes a, int index, String name) {
+               try {
+                       return Integer.valueOf(a.getValue(index + "_" + name));
+               } catch (NumberFormatException x) {
+                       return -1;
+               }
+       }
+
+       protected ImageSet createImageSet() {
+               return new ImageSet();
+       }
+
+       JarInputStream openJar() throws IOException {
+               return new JarInputStream(new FileInputStream(source));
+       }
+
+       public ImageSet[] getImageSet(String setName) throws IOException {
+               List<ImageSet> list;
+               try (JarInputStream jis = openJar()) {
+                       list = new ArrayList<>();
+                       Manifest man = jis.getManifest();
+                       Attributes a = man.getAttributes(setName);
+                       int count = Integer.valueOf(a.getValue("count"));
+                       for (int i = 0; i < count; i++) {
+                               ImageSet set = createImageSet();
+
+                               set.name = a.getValue(i + "_name");
+                               set.source = a.getValue(i + "_source");
+                               set.gid = getInt(a, i, "gid");
+                               set.count = getInt(a, i, "count");
+                               set.width = getInt(a, i, "width");
+                               set.height = getInt(a, i, "height");
+
+                               // Load it straight away?
+
+                               list.add(set);
+                       }
+               }
+
+               return list.toArray(new ImageSet[list.size()]);
+       }
+
+       public class ImageSet {
+
+               public String name;
+               public String source;
+               public int gid;
+               public int count;
+               public int width;
+               public int height;
+
+               public ImageSet() {
+               }
+
+               public void load() throws IOException {
+               }
+
+               public InputStream getInputStream() throws IOException {
+                       JarInputStream jis = null;
+                       try {
+                               jis = openJar();
+                               JarEntry je;
+
+                               System.out.println("Looking for: " + source);
+
+                               while ((je = jis.getNextJarEntry()) != null) {
+                                       System.out.println("je = " + je.getName());
+                                       if (je.getName().equals(source))
+                                               return jis;
+                               }
+                               jis.close();
+                               throw new FileNotFoundException(source);
+                       } catch (IOException ex) {
+                               if (jis != null)
+                                       jis.close();
+                               throw ex;
+                       }
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/Direction.java b/DuskZ/src/duskz/client/Direction.java
new file mode 100644 (file)
index 0000000..42ae5ac
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package duskz.client;
+
+/**
+ * Enumeration for direction commands.
+ * @author notzed
+ */
+public enum Direction {
+       North("n"),
+       South("s"),
+       East("e"),
+       West("w");
+
+       String cmd;
+       private Direction(String cmd) {
+               this.cmd = cmd;
+       }
+       
+       
+}
diff --git a/DuskZ/src/duskz/client/Dusk.java b/DuskZ/src/duskz/client/Dusk.java
new file mode 100644 (file)
index 0000000..aedb57f
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Special Thanks to:
+ * Randall Leeds for the following code portions
+ * as well as many other small changes and deprecation fixes:
+ * Float/Unfloat
+ * Joe Alloway for shadowed text and the !set command
+ *
+ * Changes
+ * Feb-2013 Michael Zucchi - modernised java, cleanup, abstracted the GUI behind
+ * an interface. Abstracted most commands. Added some binary protocol changes.
+ * Track the player id for better battles.
+ */
+package duskz.client;
+
+import duskz.protocol.MessageType;
+import duskz.protocol.ServerMessage;
+import duskz.protocol.ServerMessage.EntityMessage;
+import java.io.*;
+import java.net.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * TODO: I've removed <rgb r g b>text</rgb> colour text for now, implementation
+ * was poor TODO: applet stuff is removed FIXME: sound is all disabled
+ *
+ * @author notzed
+ */
+public class Dusk implements Runnable {
+
+       public final static boolean dumpRaw = false;
+       static String strVersion = "2.7.1.W3";
+       Status status = new Status();
+       long loncash;
+       boolean loaded,
+                       blnMenuRefresh,
+                       connected = false,
+                       blnApplet;
+       int intMusicTypes;
+       int intNumSongs[];
+       // FIXME: applet will have a different frontend or something
+       //AudioClip audSFX[],   audMusic[][];
+       //AudioClip audMusicPlaying;
+       String rcLocation;
+       List<TransactionItem> buyList = new ArrayList<>();
+       List<TransactionItem> sellList = new ArrayList<>();
+       Equipment worn = new Equipment();
+       Socket socket;
+       DataOutputStream outstream;
+       DataInputStream instream;
+       int mapSize = 11;
+       ClientMap map;
+       boolean intStep,
+                       blnMusic = true;
+       Thread thrRun;
+       int tileSize = 32;
+       int spriteSize = 64;
+       GUI frame;
+       String address = "dusk.wesowin.org";
+       int port = 7423;
+
+       public Dusk(GUI gui) {
+               frame = gui;
+               frame.setGame(this);
+       }
+
+       public void startUp() {
+               try {
+                       //frame.initComponents();
+                       //frame.setVisible(true);
+                       frame.logClear();
+                       frame.log("Dusk Client v" + strVersion + " -- http://FIXME/\n");
+                       frame.log("You are using Java version " + System.getProperty("java.version") + "\n");
+
+                       if (blnApplet) {
+                               //address = appShell.getParameter("address");
+                               //port = Integer.parseInt(appShell.getParameter("port"));
+                               connect();
+                       } else {
+                               frame.showLogin();
+                       }
+                       //thrGraphics = new GraphicsThread(this);
+                       // TODO: check if i need to set map images here
+               } catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+
+       // Main entry point
+       //static public void main(String[] args) {
+       //      new Dusk();
+       //}
+       void connect() {
+               throw new UnsupportedOperationException();
+       }
+
+       // initial cut at automatic login stuff
+       // probably want to fix server to handle login/new account stuff separately
+       enum State {
+               // not connected
+
+               Unconnected,
+               // tcp connection made
+               Connected,
+               // Username sent
+               Username,
+               // Create a new user
+               Create,
+               // Password sent
+               Password,
+               // Password accepted
+               Ready,
+               // Waiting for race selection
+               SelectRace,
+       }
+       State state = State.Unconnected;
+       String pass;
+
+       public void connect(String address, int port, String user, String pass) {
+               // Connect to Server
+               try {
+                       socket = new Socket(address, port);
+                       outstream = new DataOutputStream(socket.getOutputStream());
+                       instream = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
+                       log("Please enter your character name or the name of a new character: \n");
+
+                       state = State.Connected;
+
+                       // Load Images and start checking for incoming commands
+                       thrRun = new Thread(this);
+                       thrRun.start();
+                       connected = true;
+                       //Initialize objects
+                       map = new ClientMap(11, 11);
+                       buyList.clear();
+                       sellList.clear();
+
+                       this.pass = pass;
+                       state = State.Username;
+                       command(user);
+               } catch (Exception e) {
+                       log("Error connecting to server: " + e.toString() + "\n");
+                       return;
+               }
+       }
+
+       /**
+        * FIXME: all needs a rewrite
+        *
+        * @param entStore
+        */
+       // add the thing, this renumbers any that have the same name
+       void addEntity(Entity entStore) {
+               System.out.println("Add entity: " + entStore.ID + " " + entStore.strName);
+               map.addEntity(entStore);
+
+               // FIXME: call rement if it was out of range so the server knows
+       }
+
+       Entity findEntity(long id) {
+               return map.getEntity(id);
+       }
+
+       void removeEntity(long id) {
+               map.removeEntity(id);
+       }
+
+       void removeEntity(Entity entStore) {
+               map.removeEntity(entStore);
+       }
+
+       /**
+        * Read a . terminated list from server
+        *
+        * @return
+        */
+       List<String> readList() throws IOException {
+               List<String> l = new ArrayList<>();
+
+               String s = instream.readLine();
+               while (!s.equals(".")) {
+                       l.add(s);
+                       s = instream.readLine();
+               }
+               return l;
+       }
+
+       String readContent(String end) throws IOException {
+               StringBuilder sb = new StringBuilder();
+               String s = instream.readLine();
+
+               while (!s.equals(end)) {
+                       sb.append(s).append('\n');
+                       s = instream.readLine();
+               }
+               return sb.toString();
+       }
+
+       //Thread to process incoming commands
+       public void run() {
+               int incoming = 0;
+               while (incoming != -1) {
+                       try {
+                               // Handle incoming messages from Server
+//                 incoming = stmIn.readByte();
+                               incoming = instream.read();
+
+                               if (incoming == -1) {
+                                       continue;
+                               }
+
+                               MessageType type = MessageType.fromServer(incoming);
+
+                               System.out.println("state " + state + " incoming = " + type);
+
+                               // Hack to auto-login to server
+                               switch (state) {
+                                       case Username:
+                                               if (type == MessageType.Chat) {
+                                                       String s = instream.readLine();
+                                                       System.out.println("username: text: " + s);
+                                                       if (s.equals("enter your password:")) {
+                                                               state = State.Password;
+                                                               command(pass);
+                                                       } else if (s.endsWith("Is that correct? (yes/no)")) {
+                                                               // "new user" shit
+                                                               state = state.Create;
+                                                               command("yes");
+                                                       }
+                                               }
+                                               continue;
+                                       case Password:
+                                               if (type == MessageType.Chat) {
+                                                       String s = instream.readLine();
+                                                       System.out.println("password: text: " + s);
+                                                       if (s.equals("Login Accepted.")) {
+                                                               state = State.Ready;
+                                                               frame.loginOk();
+                                                       } else if (s.equals("Incorrect Password.")) {
+                                                               // blah blah what now?
+                                                               state = state.Connected;
+                                                       }
+                                               }
+                                               continue;
+                                       case Create:
+                                               if (type == MessageType.Chat) {
+                                                       String s = instream.readLine();
+                                                       System.out.println("create: text: " + s);
+                                                       if (s.equals("Enter a new password:")) {
+                                                               command(pass);
+                                                       } else if (s.equals("Confirm that password:")) {
+                                                               //state = State.Password;
+                                                               command(pass);
+                                                       } else if (s.equals("Login Accepted.")) {
+                                                               // this should now ask for a race
+                                                               state = State.Ready;
+                                                               frame.loginOk();
+                                                       }
+                                                       // TODO: find out what happens if that doesn't work
+                                               }
+                                               continue;
+                                       case SelectRace:
+                                               switch (type) {
+                                                       case ChooseRace:
+                                                               // Bad choice, try again
+                                                               handleChooseRace(instream);
+                                                               continue;
+                                                       default:
+                                                               state = State.Ready;
+                                                       // any other message drop through to process
+                                               }
+                                               break;
+                               }
+
+                               switch (type) {
+                                       case Quit: //Quit
+                                       {
+                                               loaded = false;
+                                               connected = false;
+                                               socket.close();
+                                               return;
+                                       }
+                                       case UpdateImages: //update Images
+                                       {
+                                               rcLocation = instream.readLine();
+                                               // FIXME: not if applet or something?
+                                               rcLocation = "rc/" + rcLocation;
+
+                                               frame.setImages(new File(rcLocation + "/images/map.gif").toURI().toString(), 32,
+                                                               new File(rcLocation + "/images/players.gif").toURI().toString(), 64,
+                                                               new File(rcLocation + "/images/sprites.gif").toURI().toString(), 64);
+                                               update();
+                                               break;
+                                       }
+                                       case UpdateLocMap: {
+                                               /*
+                                                status.updateLocation(instream);
+                                                System.out.printf("Updating map to %d %d map size %d %d\n",
+                                                status.locx, status.locy, mapSize, mapSize);
+                                                map.updateTiles(status.locx - (map.cols - 1) / 2, status.locy - (map.rows - 1) / 2, instream);
+                                                */
+                                               ServerMessage.MapMessage msg = ServerMessage.MapMessage.decode(instream);
+                                               status.updateLocation(msg.x, msg.y);
+                                               map.updateTiles(msg.x - (map.cols - 1) / 2, msg.y - (map.rows - 1) / 2, msg.map);
+                                               update();
+                                               frame.setStatus(status);
+                                               //frame.info.setText("HP: " + inthp + "/" + intmaxhp + " MP: " + intsp + "/" + intmaxsp + " Loc: " + LocX + "/" + LocY);
+                                               buyList.clear();
+                                               reloadChoiceLookGetAttack();
+                                               //paint();
+                                               break;
+                                       }
+                                       case Chat: //incoming chat
+                                       {
+                                               chat(instream.readLine() + "\n");
+                                               break;
+                                       }
+                                       case AddEntity: //add Entity
+                                       {
+                                               /*
+                                                String s = instream.readLine();
+                                                int etype = Byte.parseByte(instream.readLine());
+                                                Entity ent = null;
+                                                if (etype == 0) {
+                                                try {
+                                                ent = new Entity(s,
+                                                Long.parseLong(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                etype);
+                                                } catch (NullPointerException e) {
+                                                ent = null;
+                                                }
+                                                } else {
+                                                try {
+                                                ent = new Entity(s,
+                                                Long.parseLong(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                Integer.parseInt(instream.readLine()),
+                                                -1,
+                                                etype);
+                                                } catch (NullPointerException e) {
+                                                ent = null;
+                                                }
+                                                }*/
+                                               EntityMessage msg = ServerMessage.EntityMessage.decode(type, instream);
+                                               if (msg != null) {
+                                                       addEntity(new Entity(msg));
+                                               }
+                                               reloadChoiceLookGetAttack();
+                                               update();
+                                               break;
+                                       }
+                                       case UpdateStats: //update Stats
+                                       {
+                                               status.updateStatus(instream);
+                                               frame.setStatus(status);
+                                               break;
+                                       }
+                                       case UpdateItems: //update Items
+                                       {
+                                               worn.updateAvailable(instream);
+                                               frame.setDropList(worn.all);
+                                               frame.setEquipment(worn);
+                                               break;
+                                       }
+                                       case UpdateEquipment: //update Equipment
+                                       {
+                                               worn.updateWorn(instream);
+                                               frame.setEquipment(worn);
+                                               break;
+                                       }
+                                       case UpdateInfo: //update Stats
+                                       {
+                                               try {
+                                                       StringBuilder sb = new StringBuilder();
+                                                       String s = instream.readLine();
+                                                       while (!s.equals(".")) {
+                                                               sb.append(s);
+                                                               sb.append("\n");
+                                                               s = instream.readLine();
+                                                       }
+                                                       frame.setStats(sb.toString());
+                                               } catch (Exception e) {
+                                                       System.err.println("Error loading stats" + e.toString());
+                                               }
+                                               break;
+                                       }
+                                       case Halt: //halt
+                                       {
+                                               loaded = false;
+                                               break;
+                                       }
+                                       case UpdateActions: //update Actions
+                                       {
+                                               frame.setActionList(readList());
+                                               break;
+                                       }
+                                       case LoadMusic: //load music
+                                       {
+                                               try {
+                                                       // FIXME; applet
+                                                       /*
+                                                        if (blnApplet) {
+                                                        log("Loading music.\n");
+                                                        intMusicTypes = Integer.parseInt(instream.readLine());
+                                                        audMusic = new AudioClip[intMusicTypes][];
+                                                        intNumSongs = new int[intMusicTypes];
+                                                        for (intStore = 0; intStore < intMusicTypes; intStore++) {
+                                                        intNumSongs[intStore] = Integer.parseInt(instream.readLine());
+                                                        audMusic[intStore] = new AudioClip[intNumSongs[intStore]];
+                                                        for (intStore2 = 0; intStore2 < intNumSongs[intStore]; intStore2++) {
+                                                        String s = instream.readLine();
+                                                        try {
+                                                        //audMusic[intStore][intStore2] = appShell.getAudioClip(new URL(strStore));
+                                                        while (audMusic[intStore][intStore2] == null) {
+                                                        }
+                                                        } catch (Exception e) {
+                                                        System.err.println("Error while trying to load music file " + s + ":" + e.toString());
+                                                        }
+                                                        }
+                                                        }
+                                                        log("Music loaded.\n");
+                                                        }*/
+                                               } catch (Exception e) {
+                                                       blnMusic = false;
+                                                       log("Your java virtual machine does not support midi music\n");
+                                                       System.err.println("Error while trying to load music files:" + e.toString());
+                                               }
+                                               break;
+                                       }
+                                       case PlayMusic: //play music
+                                       {
+                                               if (blnMusic) {
+                                                       /* FIXME: sound
+                                                        try {
+                                                        intStore = Integer.parseInt(instream.readLine());
+                                                        if (audMusicPlaying != null) {
+                                                        audMusicPlaying.stop();
+                                                        }
+                                                        audMusicPlaying = audMusic[intStore][(int) (Math.random() * intNumSongs[intStore])];
+                                                        audMusicPlaying.loop();
+                                                        } catch (Exception e) {
+                                                        System.err.println("Error while trying to play music file:" + e.toString());
+                                                        }*/
+                                               }
+                                               break;
+                                       }
+                                       case Ping: //stillThere?
+                                       {
+                                               outstream.writeBytes("notdead\n");
+                                               break;
+                                       }
+                                       case Proceed: //proceed
+                                       {
+                                               status.id = Long.parseLong(instream.readLine());
+                                               loaded = true;
+                                               break;
+                                       }
+                                       case PlaySound: //play sfx
+                                       {
+                                               try {
+                                                       //audSFX[Integer.parseInt(instream.readLine())].play();
+                                               } catch (Exception e) {
+                                               }
+                                               break;
+                                       }
+                                       case RemoveEntity: //remove entity
+                                       {
+                                               long id = Long.valueOf(instream.readLine()).longValue();
+
+                                               removeEntity(id);
+                                               reloadChoiceLookGetAttack();
+                                               update();
+                                               break;
+                                       }
+                                       case UpdateMerchant: //update Merchant
+                                       {
+                                               buyList = TransactionItem.createItems(readList());
+                                               frame.setBuyList(buyList);
+                                               break;
+                                       }
+                                       case EditText: //view/edit
+                                       {
+                                               String name = instream.readLine();
+                                               frame.visitFile(name, readContent("--EOF--"), true);
+                                               break;
+                                       }
+                                       case ResizeMap: //resize Map
+                                       {
+                                               mapSize = Integer.parseInt(instream.readLine());
+                                               map = new ClientMap(mapSize, mapSize);
+                                               if (blnApplet) {
+                                                       outstream.writeBytes("appletimages\n");
+                                               } else {
+                                                       outstream.writeBytes("applicationimages\n");
+                                               }
+                                               //scaleWindow();
+                                               break;
+                                       }
+                                       case ViewText: //view/no-edit
+                                       {
+                                               String name = instream.readLine();
+                                               frame.visitFile(name, readContent("--EOF--"), false);
+                                               break;
+                                       }
+                                       case ExitMerchant: //offMerchant
+                                       {
+                                               frame.exitShop();
+                                               buyList.clear();
+                                               sellList.clear();
+                                               break;
+                                       }
+                                       case UpdateSell: //update Sell
+                                       {
+                                               sellList = TransactionItem.createItems(readList());
+                                               frame.setSellList(sellList);
+                                               break;
+                                       }
+                                       case ColourChat: //colour chat
+                                       {
+                                               // FIXME: re-implement colour, or probably fix it (hex codes)
+                                               instream.readLine();
+                                               instream.readLine();
+                                               instream.readLine();
+                                               chat(instream.readLine() + "\n");
+                                               break;
+                                       }
+                                       case MoveNorth: //move north
+                                       {
+                                               long ID = Long.parseLong(instream.readLine());
+
+                                               handleMove(ID, 1, 0, -1, 0);
+                                               break;
+                                       }
+                                       case MoveSouth: //move south
+                                       {
+                                               long ID = Long.parseLong(instream.readLine());
+
+                                               handleMove(ID, 3, 0, 1, 1);
+                                               break;
+                                       }
+                                       case MoveWest: //move west
+                                       {
+                                               long ID = Long.parseLong(instream.readLine());
+
+                                               handleMove(ID, 5, -1, 0, 2);
+                                               break;
+                                       }
+                                       case MoveEast: //move east
+                                       {
+                                               long ID = Long.parseLong(instream.readLine());
+
+                                               handleMove(ID, 7, 1, 0, 3);
+                                               break;
+                                       }
+                                       case UpdateRange: //update range
+                                       {
+                                               status.range = Integer.parseInt(instream.readLine());
+                                               break;
+                                       }
+                                       case SetFlag: //set flag
+                                       {
+                                               long id = Long.valueOf(instream.readLine()).longValue();
+                                               int flags = Integer.parseInt(instream.readLine());
+
+                                               Entity e = map.getEntity(id);
+                                               if (e != null) {
+                                                       e.intFlag = flags;
+                                                       update();
+                                               } else {
+                                                       log("Error: set flag on unknown entity: " + id);
+                                               }
+                                               break;
+                                       }
+                                       case ClearFlags: //clear all flags
+                                       {
+                                               // FIXME: hideinfo?
+                                               synchronized (map) {
+                                                       for (Entity e : map.getEntities()) {
+                                                               e.intFlag = 0;
+                                                       }
+                                               }
+                                               update();
+                                               break;
+                                       }
+                                       case StartBattle: //show battle window and clear text
+                                       {
+                                               // FIXME: no battle popup window at the moment
+                                               String s = instream.readLine();
+                                               battle("Battle started: " + s + "\n");
+                                               break;
+                                       }
+                                       case UpdateBattle: //show battle window and update title
+                                       {
+                                               // FIXME: no battle popup window at the moment
+                                               String s = instream.readLine();
+                                               battle("Battle status: " + s + "\n");
+                                               break;
+                                       }
+                                       case LogBattle: //add text to battle window
+                                       {
+                                               // FIXME: no battle popup window at the moment
+                                               String s = instream.readLine();
+                                               battle(s + "\n");
+                                               break;
+                                       }
+                                       case ChooseRace:
+                                               handleChooseRace(instream);
+                                               break;
+                                       case HitEntity: {
+                                               long toID = Long.valueOf(instream.readLine());
+                                               int delta = -Integer.valueOf(instream.readLine());
+                                               int newhp = Integer.valueOf(instream.readLine());
+                                               int tothp = Integer.valueOf(instream.readLine());
+                                               long fromID = Long.valueOf(instream.readLine());
+                                               String how = instream.readLine();
+
+                                               String s;
+                                               do {
+                                                       s = instream.readLine();
+                                               } while (!s.equals("."));
+
+                                               System.out.printf("entity %d %s delta %d hp %d/%d\n",
+                                                               toID, how, delta, newhp, tothp);
+
+                                               // TODO: I should have who from/to this damage is
+                                               Entity f = findEntity(fromID);
+                                               Entity e = findEntity(toID);
+                                               if (e != null) {
+                                                       double xloc = map.mapToLocalX(e.locx),
+                                                                       yloc = map.mapToLocalY(e.locy);
+
+                                                       // Get angle to entity from player
+                                                       double a = Math.PI;
+                                                       if (f != null) {
+                                                               a = Math.atan2(e.locy - f.locy, e.locx - f.locx);
+                                                       }
+
+                                                       frame.damageEntity(e, a, xloc * tileSize, yloc * tileSize, delta, how);
+                                               } else {
+                                                       System.out.println("Unknown entity");
+                                               }
+
+                                               break;
+                                       }
+                               }
+                       } catch (Exception e) {
+                               System.err.println("Error at run() with value " + incoming + " : " + e.toString());
+                               e.printStackTrace(System.out);
+
+                               log("Error at run() with value " + incoming + " : " + e.toString() + "\n");
+                               connected = false;
+                               return;
+                       }
+               }
+               System.err.println("Error at run() with value " + incoming);
+       }
+
+       private void handleMove(long ID, int step, int dx, int dy, int dir) {
+               Entity e = map.getEntity(ID);
+
+               if (e == null) {
+                       System.out.println("move unknown entity: " + ID);
+                       return;
+               }
+
+               map.moveEntity(e, e.locx + dx, e.locy + dy);
+               if (e.intStep != -1) {
+                       // Toggle through the 2 animations for movement
+                       if (e.intMoveDirection == dir) {
+                               e.intStep ^= 1;
+                       } else {
+                               e.intStep = step;
+                               e.intMoveDirection = dir;
+                       }
+               }
+               reloadChoiceAttack();
+               // TODO: find out what this is for
+               //if (addit) {
+               //      thrGraphics.addEntityToMove(ent, dir);
+               //}
+               // HACK: Don't update the screen display if the user moves, attempted
+               // fix at flicker-on-move stuff.
+               // The server should always send an UpdateLocMap every time
+               if (ID != status.id) {
+                       update();
+               }
+       }
+
+       private void handleChooseRace(DataInputStream in) throws IOException {
+               List<String> races = new ArrayList<>();
+               String prompt = in.readLine();
+               String l = in.readLine();
+               while (!l.equals(".")) {
+                       races.add(l);
+                       l = in.readLine();
+               }
+               state = State.SelectRace;
+               frame.chooseRace(prompt, races);
+       }
+
+       public void chooseRace(String race) {
+               if (state == State.SelectRace) {
+                       command(race);
+               }
+       }
+
+       // TBD - use the individual functions
+       public void reloadChoiceLookGetAttack() {
+               final ArrayList<Entity> looks = new ArrayList<>();
+               final ArrayList<Entity> gets = new ArrayList<>();
+               final ArrayList<Entity> attacks = new ArrayList<>();
+
+               synchronized (map) {
+                       for (Entity e : map.getEntities()) {
+                               if (status.canLook(e))
+                                       looks.add(e);
+
+                               if (status.canTake(e))
+                                       gets.add(e);
+
+                               if (status.canAttack(e))
+                                       attacks.add(e);
+                       }
+               }
+
+               frame.setLookList(looks);
+               frame.setAttackList(attacks);
+               frame.setTakeList(gets);
+       }
+
+       public void reloadChoiceLook() {
+               final ArrayList<Entity> looks = new ArrayList<>();
+
+               synchronized (map) {
+                       for (Entity e : map.getEntities()) {
+                               if (status.canLook(e))
+                                       looks.add(e);
+                       }
+               }
+               frame.setLookList(looks);
+       }
+
+       public void reloadChoiceAttack() {
+               final ArrayList<Entity> attacks = new ArrayList<>();
+
+               synchronized (map) {
+                       for (Entity e : map.getEntities()) {
+                               if (status.canAttack(e))
+                                       attacks.add(e);
+                       }
+               }
+               frame.setAttackList(attacks);
+       }
+
+       public void reloadChoiceGet() {
+               final ArrayList<Entity> gets = new ArrayList<>();
+
+               synchronized (map) {
+                       for (Entity e : map.getEntities()) {
+                               if (status.canTake(e))
+                                       gets.add(e);
+                       }
+               }
+               frame.setTakeList(gets);
+       }
+
+       public boolean isConnected() {
+               return connected;
+       }
+
+       public boolean isLoaded() {
+               return loaded;
+       }
+
+       public int getTileSize() {
+               return tileSize;
+       }
+
+       /**
+        * Offset y to origin of displayed map
+        *
+        * @return
+        */
+       public int getMapOffsetX() {
+               return map.offx;
+       }
+
+       /**
+        * Offset y to origin of displayed map
+        *
+        * @return
+        */
+       public int getMapOffsetY() {
+               return map.offy;
+       }
+
+       public void userconnect() {
+               //frame.frmConnect.show();
+               //frame.frmConnect.setSize(350, 200);
+               System.out.println("user ocnnect not implemented - quit and restart");
+       }
+
+       public void equipment() {
+               frame.manageEquipment(worn);
+       }
+
+       public void merchant() {
+               frame.enterShop("Merchant", buyList, sellList);
+       }
+
+       // these all do the same thing at the moment, but could allow
+       // for alternative output for various things
+       // FIXME: chat needs the source id as well
+       public void chat(String txt) {
+               frame.log(txt);
+       }
+
+       public void battle(String txt) {
+               System.out.println("battle: " + txt);
+               frame.log(txt);
+       }
+
+       public void log(String txt) {
+               frame.log(txt);
+       }
+
+       public void logout() {
+               try {
+                       if (connected) {
+                               outstream.writeBytes("quit\n");
+                       }
+               } catch (Exception exc) {
+               }
+               try {
+                       socket.close();
+               } catch (Exception exc) {
+               }
+               socket = null;
+               connected = false;
+       }
+
+       public void quit() {
+               try {
+                       if (connected) {
+                               outstream.writeBytes("quit\n");
+                       }
+               } catch (Exception exc) {
+               }
+               try {
+                       socket.close();
+               } catch (Exception exc) {
+               }
+               System.gc();
+               if (blnApplet) {
+                       //appShell.destroy();
+               } else {
+                       // FIXME: wrong!
+                       System.exit(0);
+               }
+
+       }
+
+       //Display graphics
+       public void update() {
+               synchronized (map) {
+                       frame.updateMap(map);
+               }
+       }
+
+       private void docmd(String cmd) {
+               System.out.println("send command: " + cmd);
+               try {
+                       outstream.writeBytes(cmd);
+               } catch (IOException ex) {
+                       // TODO: close connection here
+                       Logger.getLogger(Dusk.class.getName()).log(Level.SEVERE, null, ex);
+               }
+       }
+
+       public void command(String what) {
+               docmd(what + "\n");
+       }
+
+       public void command(String what, String params) {
+               docmd(what + " " + params + "\n");
+       }
+
+       public void move(Direction dir) {
+               command(dir.cmd);
+       }
+
+       public void moveTo(int dx, int dy) {
+               //Move to location
+               try {
+                       System.out.println("goto " + dx + "," + dy);
+                       outstream.writeBytes("goto " + dx + " " + dy + "\n");
+               } catch (Exception e) {
+                       frame.log("Error in goto %d,%d: %s", dx, dy, e);
+               }
+       }
+
+       public void buy(TransactionItem item, int quantity) {
+               command("buy " + quantity + " " + item.name);
+       }
+
+       public void sell(TransactionItem item, int quantity) {
+               command("sell " + quantity + " " + item.name);
+       }
+
+       // TODO: find out why these uses the base name and ignores the numbers.
+       public void attack(Entity e) {
+               command("a " + e.ID);
+       }
+
+       public void look(Entity e) {
+               command("look " + e.ID);
+       }
+
+       public void take(Entity e) {
+               command("get " + e.ID);
+       }
+
+       public void drop(String what) {
+               command("drop " + what);
+       }
+
+       public void wear(String what) {
+               command("wear " + what);
+       }
+
+       public void unwear(String what) {
+               command("unwear " + what);
+       }
+}
diff --git a/DuskZ/src/duskz/client/Entity.java b/DuskZ/src/duskz/client/Entity.java
new file mode 100644 (file)
index 0000000..f141c10
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - some helper/accessors.
+ */
+package duskz.client;
+
+import duskz.protocol.ServerMessage;
+
+public class Entity {
+
+       public String strName;
+       public int locx,
+                       locy;
+       public int intType,
+                       intNum = 0,
+                       intStep = -1,
+                       intImage = 0,
+                       intTicks,
+                       intMoveDirection = -1,
+                       /*intMoveDirection
+                        0 north
+                        1 south
+                        2 west
+                        3 east
+                        */
+                       intFlag = 0;
+       /*intFlag
+        0 none
+        1 ally
+        2 enemy
+        */
+       long ID;
+       Entity entNext = null;
+
+       public Entity(String instrName, long inID, int inintLocX, int inintLocY, int inImage, int inStep, int inintType) {
+               strName = instrName;
+               ID = inID;
+               locx = inintLocX;
+               locy = inintLocY;
+               intImage = inImage;
+               intStep = inStep;
+               intType = inintType;
+       }
+
+       public Entity(ServerMessage.EntityMessage msg) {
+               strName = msg.name;
+               locx = msg.x;
+               locy = msg.y;
+               ID = msg.id;
+               intType = msg.entityType;
+               intImage = msg.image;
+               intStep = msg.imageStep;
+       }
+
+       /**
+        * Returns name without status attributes
+        *
+        * @return
+        */
+       public String getSimpleName() {
+               int i = strName.lastIndexOf(">");
+               if (i != -1) {
+                       return strName.substring(i + 1);
+               } else {
+                       return strName;
+               }
+       }
+
+       public String getIndexedName() {
+               return intNum == 0 ? strName : intNum + "." + strName;
+       }
+
+       @Override
+       public String toString() {
+
+               return "[Entity " + ID + ", " + strName + ", " + locx + ", " + locy + "]";
+       }
+}
diff --git a/DuskZ/src/duskz/client/Equipment.java b/DuskZ/src/duskz/client/Equipment.java
new file mode 100644 (file)
index 0000000..b988c77
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client;
+
+import duskz.protocol.Wearing;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This is a bit junk.
+ * Server code also has a similar mess
+ *
+ * @author notzed
+ */
+public class Equipment implements Wearing {
+
+       /**
+        * Worn items
+        */
+       public String[] worn = new String[WEARING_COUNT];
+       /**
+        * Available items for wearing
+        */
+       public List<String>[] available = new List[WEARING_COUNT];
+       /**
+        * All items
+        */
+       public List<String> all = new ArrayList<>();
+       /**
+        * Where is item wearable at?
+        * FIXME: maybe i should just store them in a structure
+        */
+       HashMap<String, Integer> wearableAt = new HashMap<>();
+
+       public Equipment() {
+               for (int i = 0; i < available.length; i++)
+                       available[i] = new ArrayList<>();
+       }
+
+       public int canWearAt(String what) {
+               Integer i = wearableAt.get(what);
+
+               if (i == null)
+                       return -1;
+               return i;
+       }
+
+       /**
+        * Returns where what is worn at, if at all.
+        *
+        * @param what
+        * @return -1 if not worn
+        */
+       public int wearingAt(String what) {
+               for (int i = 0; i < worn.length; i++)
+                       if (worn[i].equals(what))
+                               return i;
+               return -1;
+       }
+
+       /**
+        * Decode worn from network
+        *
+        * @return
+        */
+       public void updateWorn(DataInputStream instream) throws IOException {
+               for (int i = 0; i < worn.length; i++) {
+                       worn[i] = instream.readLine();
+                       System.out.println(" worn: " + worn[i]);
+               }
+       }
+
+       public void updateAvailable(DataInputStream instream) throws IOException, NumberFormatException {
+               String line;
+
+               all.clear();
+               for (int i = 0; i < available.length; i++)
+                       available[i].clear();
+               wearableAt.clear();
+
+               while ((line = instream.readLine()) != null && !line.equals(".")) {
+                       // Need to map from server 'id' to our index
+                       int i = Integer.parseInt(line) - 1;
+                       String s = instream.readLine();
+
+                       System.out.println(" " + i + " " + s);
+
+                       if (i >= 0 && i < available.length) {
+                               available[i].add(s);
+                               wearableAt.put(s, i);
+                       }
+                       all.add(s);
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/GUI.java b/DuskZ/src/duskz/client/GUI.java
new file mode 100644 (file)
index 0000000..a6dace1
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client;
+
+import java.util.List;
+
+/**
+ * Interface for all gui interactions.
+ *
+ * To implement a different frontend toolkit, simply pass this to the Dusk
+ * constructor.
+ *
+ * @author notzed
+ */
+public interface GUI {
+
+       /**
+        * Init, should be called before anything else
+        */
+       public void setGame(Dusk aThis);
+
+       /**
+        * Clear output log, i.e. start of game
+        */
+       public void logClear();
+
+       /**
+        * Log something to the log window
+        *
+        * @param txt
+        */
+       public GUI log(String txt, Object... args);
+       // Init/login
+
+       public void showLogin();
+
+       public void loginOk();
+
+       public void chooseRace(String prompt, List<String> races);
+
+       /**
+        * Show the shop window
+        *
+        * @param title
+        * @param buyList
+        * @param sellList
+        */
+       public void enterShop(String title, List<TransactionItem> buyList, List<TransactionItem> sellList);
+
+       /**
+        * Update the buy list whilst in the shop
+        *
+        * @param buyList
+        */
+       public void setBuyList(List<TransactionItem> buyList);
+
+       /**
+        * Update the sell list whilst in the shop
+        *
+        * @param sellList
+        */
+       public void setSellList(List<TransactionItem> sellList);
+
+       /**
+        * Close the shop window
+        */
+       public void exitShop();
+
+       /**
+        * Open the equipment window
+        *
+        * @param worn
+        */
+       public void manageEquipment(Equipment worn);
+
+       /**
+        * Update the won list, i.e. if in inventory/equipment screen
+        *
+        * @param worn
+        */
+       public void setEquipment(Equipment worn);
+
+       // Misc high level functions
+       public void visitFile(String file, String text, boolean canSave);
+
+       // TODO: parse the content
+       public void setStats(String stats);
+
+       /**
+        * Set hp/mp etc status.
+        *
+        * @param status
+        */
+       public void setStatus(Status status);
+
+       public void setTakeList(List<Entity> list);
+
+       public void setDropList(List<String> list);
+
+       public void setActionList(List<String> list);
+
+       public void setAttackList(List<Entity> list);
+
+       public void setLookList(List<Entity> list);
+
+       // setup/map
+       public void setImages(String tiles, int tileSize, String players, int playerSize, String sprites, int spriteSize);
+
+       /**
+        * Update the map.
+        *
+        * @param map Source map
+        */
+       public void updateMap(ClientMap map);
+
+       /**
+        * Display or log some damage
+        * TODO: use a servermessage for the details
+        * @param e
+        * @param angle angle to attacker
+        * @param locx
+        * @param locy
+        * @param delta how much damage
+        * @param how how it was caused
+        */
+       public void damageEntity(Entity e, double angle, double locx, double locy, int delta, String how);
+}
diff --git a/DuskZ/src/duskz/client/Status.java b/DuskZ/src/duskz/client/Status.java
new file mode 100644 (file)
index 0000000..a6efd0e
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - encapsulated a bunch of code out of Dusk
+ * to track the status.
+ */
+package duskz.client;
+
+import java.io.DataInputStream;
+import java.io.IOException;
+
+/**
+ * Current player information
+ *
+ * @author notzed
+ */
+public class Status {
+
+       long id;
+       // Attack range
+       int range = 1;
+       int hp, maxhp;
+       int mp, maxmp;
+       int locx, locy;
+
+       public void updateStatus(DataInputStream instream) throws IOException {
+               hp = Integer.parseInt(instream.readLine());
+               maxhp = Integer.parseInt(instream.readLine());
+               mp = Integer.parseInt(instream.readLine());
+               maxmp = Integer.parseInt(instream.readLine());
+       }
+
+       public void updateLocation(int x, int y) {
+               locx = x;
+               locy = y;
+       }
+
+       public void updateLocation(DataInputStream instream) throws IOException {
+               //locx = Integer.parseInt(instream.readLine());
+               //locy = Integer.parseInt(instream.readLine());
+               locx = instream.readShort();
+               locy = instream.readShort();
+       }
+
+       @Override
+       public String toString() {
+               return "HP: " + hp + "/" + maxhp + " MP: " + mp + "/" + maxmp + " Loc: " + locx + "/" + locy;
+       }
+
+       public int distance(Entity e) {
+               return Math.abs(locx - e.locx) + Math.abs(locy - e.locy);
+       }
+
+       public boolean canLook(Entity e) {
+               return true;
+       }
+
+       public boolean canTake(Entity e) {
+               return e.intType == 1
+                               && (distance(e) < 2);
+       }
+
+       public boolean canAttack(Entity e) {
+               return e.ID != id
+                               && ((e.intType == 0 || e.intType == 1 || e.intType == 4)
+                               && (distance(e) <= range));
+       }
+}
diff --git a/DuskZ/src/duskz/client/TransactionItem.java b/DuskZ/src/duskz/client/TransactionItem.java
new file mode 100644 (file)
index 0000000..910b873
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+package duskz.client;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Takes a server response and parses it into a name/cost/count
+ * list suitable for a toolkit.
+ *
+ * @deprecated should be merged with DuskCommon's TransactionItem
+ * @author notzed
+ */
+@Deprecated
+public class TransactionItem implements Comparable<TransactionItem> {
+
+       public String cost;
+       public int count;
+       public String name;
+
+       /**
+        * Convert a list of items as from the server into a list of
+        * transaction items.
+        * i.e. count them up, separate cost.
+        *
+        * @param source
+        * @return
+        */
+       public static List<TransactionItem> createItems(List<String> source) {
+               List<TransactionItem> list = new ArrayList<>();
+
+               Collections.sort(source);
+               TransactionItem last = null;
+               String lastName = null;
+               for (String s : source) {
+                       if (lastName != null && lastName.equals(s)) {
+                               last.count++;
+                       } else {
+                               int i;
+
+                               last = new TransactionItem();
+                               last.count = 1;
+
+                               i = s.indexOf(')');
+                               if (i != -1) {
+                                       last.cost = s.substring(0, i);
+                                       last.name = s.substring(i + 1);
+                               } else {
+                                       last.name = s;
+                                       last.cost = "";
+                               }
+                               list.add(last);
+                       }
+                       lastName = s;
+               }
+               Collections.sort(list);
+               return list;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public int getCount() {
+               return count;
+       }
+
+       public String getCost() {
+               return cost;
+       }
+
+       @Override
+       public String toString() {
+               return cost + ") " + name + "[" + count + "]";
+       }
+
+       @Override
+       public int compareTo(TransactionItem t) {
+               return name.compareTo(t.name);
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/DataManagerFX.java b/DuskZ/src/duskz/client/fx/DataManagerFX.java
new file mode 100644 (file)
index 0000000..5720ed2
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client.fx;
+
+import duskz.client.DataManager;
+import java.io.IOException;
+import java.io.InputStream;
+import javafx.geometry.Rectangle2D;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+
+/**
+ * Data manager for JavaFX - loads images into Image nodes and helpers
+ * to create positioned tiles.
+ *
+ * @author notzed
+ */
+public class DataManagerFX extends DataManager {
+
+       public DataManagerFX(String source) {
+               super(source);
+       }
+
+       @Override
+       protected ImageSet createImageSet() {
+               return new ImageSetFX();
+       }
+
+       /**
+        * Create a tile image and align it to the baseline of the map tile.
+        *
+        * This assumes the tiles are the same width but height may vary
+        *
+        * @param tileid
+        * @param tilex
+        * @param tiley
+        * @param tilewidth
+        * @param tileheight
+        * @return
+        */
+       public ImageView createTile(int tileid, int tilex, int tiley, int tilewidth, int tileheight) {
+               try {
+                       for (int i = 0; i < tilesets.length; i++) {
+                               ImageSetFX is = (ImageSetFX) tilesets[i];
+                               if (tileid >= is.gid && tileid < is.gid + is.count) {
+                                       ImageView iv = new ImageView(is.image);
+
+                                       tileid -= is.gid;
+                                       iv.setViewport(new Rectangle2D(tileid * is.width, 0, is.width, is.height));
+                                       iv.relocate(tilex * tilewidth, tiley * tileheight - (is.height - tileheight));
+
+                                       return iv;
+                               }
+                       }
+               } catch (Exception x) {
+                       x.printStackTrace();
+               }
+               System.out.println("No such tile: " + tileid);
+               // Broken image?
+               return new ImageView();
+       }
+
+       public class ImageSetFX extends ImageSet {
+
+               Image image;
+
+               public ImageSetFX() {
+               }
+
+               public void load() throws IOException {
+                       System.out.println("Load tileset " + name + " gid " + gid + " count " + count);
+                       try (InputStream s = getInputStream()) {
+                               image = new Image(s);
+                       }
+               }
+
+               public Image getImage() {
+                       return image;
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/DuskFX.java b/DuskZ/src/duskz/client/fx/DuskFX.java
new file mode 100644 (file)
index 0000000..e7f8633
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client.fx;
+
+import duskz.client.Dusk;
+import javafx.application.Application;
+import javafx.scene.Scene;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyCodeCombination;
+import javafx.stage.Stage;
+
+/**
+ * Main application entry point for JavaFX frontend
+ *
+ * @author notzed
+ */
+public class DuskFX extends Application {
+
+       MainFrameFX frame;
+       Scene scene;
+       Dusk game;
+
+       @Override
+       public void start(Stage stage) {
+               frame = new MainFrameFX();
+               game = new Dusk(frame);
+
+               scene = new Scene(frame);
+               stage.setScene(scene);
+
+               scene.getAccelerators().put(new KeyCodeCombination(KeyCode.ESCAPE), new Runnable() {
+                       @Override
+                       public void run() {
+                               frame.exitWindow();
+                       }
+               });
+
+               stage.getScene().getStylesheets().add(DuskFX.class.getResource("style.css").toExternalForm());
+               stage.setTitle("DuskZ JavaFX");
+               stage.show();
+
+               game.startUp();
+       }
+
+       @Override
+       public void stop() throws Exception {
+               game.quit();
+               super.stop();
+       }
+
+       /**
+        * The main() method is ignored in correctly deployed JavaFX application.
+        *
+        * @param args the command line arguments
+        */
+       public static void main(String[] args) {
+               launch(args);
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/EquipmentPane.java b/DuskZ/src/duskz/client/fx/EquipmentPane.java
new file mode 100644 (file)
index 0000000..f515d48
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client.fx;
+
+import duskz.client.Equipment;
+import java.util.ArrayList;
+import java.util.List;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+import jfxtras.labs.scene.control.ListSpinner;
+
+/**
+ * Pane for a list of equipment with detail area and controls.
+ *
+ * @author notzed
+ */
+public class EquipmentPane extends HBox {
+
+       ListView<ItemInfo> list;
+       Label detail;
+       ListSpinner quantity;
+       Button wear, unwear, drop;
+       Equipment worn;
+
+       public EquipmentPane() {
+               setId("equipment-pane");
+
+               VBox right = new VBox();
+
+               HBox.setHgrow(right, Priority.ALWAYS);
+
+               right.setAlignment(Pos.TOP_RIGHT);
+               right.setFillWidth(true);
+
+               list = new ListView<>();
+               detail = new Label();
+               quantity = new ListSpinner(1, 100);
+
+               HBox hb;
+
+               hb = new HBox();
+               hb.setFillHeight(true);
+               VBox.setVgrow(hb, Priority.ALWAYS);
+               hb.getChildren().add(detail);
+               right.getChildren().add(hb);
+
+               wear = new Button("Wear");
+               unwear = new Button("Un-wear");
+               drop = new Button("Drop");
+
+               wear.setDisable(true);
+               unwear.setDisable(true);
+               drop.setDisable(true);
+
+               hb = new HBox();
+               hb.getChildren().addAll(wear, unwear, drop);
+               hb.setAlignment(Pos.CENTER);
+               right.getChildren().add(hb);
+
+               HBox.setHgrow(list, Priority.NEVER);
+
+               getChildren().addAll(list, right);
+
+               list.setMinWidth(310);
+               list.setMaxWidth(310);
+               list.setEditable(false);
+
+               list.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<ItemInfo>() {
+                       @Override
+                       public void changed(ObservableValue<? extends ItemInfo> ov, ItemInfo t, ItemInfo t1) {
+                               if (t1 != null) {
+                                       detail.setText(String.format("Item: %s\n\n ... some description or shit ...\n",
+                                                       t1));
+
+                                       wear.setDisable(t1.wornAt != -1 || worn.canWearAt(t1.name) == -1);
+                                       unwear.setDisable(t1.wornAt == -1);
+                                       drop.setDisable(false);
+                               } else {
+                                       detail.setText("");
+                                       wear.setDisable(true);
+                                       unwear.setDisable(true);
+                                       drop.setDisable(true);
+                               }
+                       }
+               });
+       }
+
+       public ItemInfo getItem() {
+               return list.getSelectionModel().getSelectedItem();
+       }
+
+       static class ItemInfo {
+
+               String name;
+               int wornAt;
+
+               public ItemInfo(String name, int wornAt) {
+                       this.name = name;
+                       this.wornAt = wornAt;
+               }
+
+               @Override
+               public String toString() {
+                       return wornAt == -1 ? name : name + " [worn: " + Equipment.titles[wornAt] + "]";
+               }
+       }
+
+       public void setEquipment(Equipment worn) {
+               this.worn = worn;
+
+               List<ItemInfo> items = new ArrayList<>();
+
+               for (int i = 0; i < worn.worn.length; i++) {
+                       String s = worn.worn[i];
+                       if (s != null && !s.equals("none"))
+                               items.add(new ItemInfo(s, i));
+               }
+               for (String s : worn.all) {
+                       items.add(new ItemInfo(s, -1));
+               }
+
+               list.getItems().setAll(items);
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/MainFrameFX.java b/DuskZ/src/duskz/client/fx/MainFrameFX.java
new file mode 100644 (file)
index 0000000..be60d02
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2000 Tom Weingarten <captaint@home.com>
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+/**
+ * Changes
+ * Feb-2013 Michael Zucchi - This is mostly new apart from
+ * a bit of the keyboard and mouse handler code and the structure of the
+ * rendering pass.
+ */
+package duskz.client.fx;
+
+import duskz.client.Bookmarks;
+import duskz.client.ClientMap;
+import duskz.client.Direction;
+import duskz.client.Dusk;
+import duskz.client.Entity;
+import duskz.client.Equipment;
+import duskz.client.GUI;
+import duskz.client.Status;
+import duskz.client.TransactionItem;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Random;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javafx.animation.FadeTransition;
+import javafx.animation.FadeTransitionBuilder;
+import javafx.animation.Interpolator;
+import javafx.animation.ParallelTransition;
+import javafx.animation.Transition;
+import javafx.animation.TranslateTransitionBuilder;
+import javafx.application.Platform;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.HPos;
+import javafx.geometry.Insets;
+import javafx.geometry.Pos;
+import javafx.geometry.Rectangle2D;
+import javafx.geometry.VPos;
+import javafx.scene.Node;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.ListView;
+import javafx.scene.control.MenuButton;
+import javafx.scene.control.MenuItem;
+import javafx.scene.control.MenuItemBuilder;
+import javafx.scene.control.PasswordField;
+import javafx.scene.control.Separator;
+import javafx.scene.control.Tab;
+import javafx.scene.control.TabPane;
+import javafx.scene.control.TextArea;
+import javafx.scene.control.TextField;
+import javafx.scene.effect.BoxBlur;
+import javafx.scene.effect.DropShadow;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.input.KeyCode;
+import static javafx.scene.input.KeyCode.DOWN;
+import static javafx.scene.input.KeyCode.LEFT;
+import static javafx.scene.input.KeyCode.RIGHT;
+import static javafx.scene.input.KeyCode.UP;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.StackPane;
+import javafx.scene.layout.VBox;
+import javafx.scene.paint.Color;
+import javafx.scene.shape.Rectangle;
+import javafx.scene.text.Text;
+import javafx.util.Duration;
+
+/**
+ * This is the main JavaFX window.
+ *
+ * It handles all the GUI related operations.
+ *
+ * Prototype code herein, it needs to be split out into functional windows to
+ * make it more manageable
+ *
+ * @author notzed
+ */
+public class MainFrameFX extends StackPane implements GUI {
+
+       Dusk game;
+       //
+       BorderPane main;
+       StackPane layers;
+       Pane graphics;
+       Pane battle;
+       BorderPane panel;
+       VBox buttons;
+       TextArea stats;
+       TextArea log;
+       TextField cmdLine;
+       Label info;
+       // just clone interface to start with
+       MenuButton attack, action, look, get, drop;
+       //
+       Button connect, merchant, equipment, quit;
+       /**
+        * **************
+        * Behaviour state
+        */
+       /**
+        * "!command" allows one to execute a fixed operation after every move.
+        */
+       private String postMove;
+
+       public void setGame(Dusk game) {
+               this.game = game;
+       }
+
+       public MainFrameFX() {
+               layers = new StackPane();
+
+               getChildren().add(main = new BorderPane());
+
+               layers.getChildren().addAll(graphics = new Pane(), battle = new Pane());
+
+               layers.setPrefSize(416, 416);
+               main.setCenter(layers);
+
+               //layers.setScaleX(2);
+               //layers.setScaleY(2);
+
+               panel = new BorderPane();
+               panel.setMaxWidth(320);
+               main.setRight(panel);
+
+               buttons = new VBox();
+               stats = new TextArea();
+               panel.setTop(info = new Label());
+               panel.setLeft(buttons);
+               panel.setCenter(stats);
+
+               buttons.getChildren().addAll(
+                               attack = new MenuButton("Attack"),
+                               action = new MenuButton("Action"),
+                               look = new MenuButton("Look"),
+                               get = new MenuButton("Get"),
+                               drop = new MenuButton("Drop"),
+                               connect = new Button("Connect"),
+                               merchant = new Button("Merchant"),
+                               equipment = new Button("Equipment"),
+                               quit = new Button("Quit"));
+
+               attack.setMaxWidth(Double.MAX_VALUE);
+               action.setMaxWidth(Double.MAX_VALUE);
+               look.setMaxWidth(Double.MAX_VALUE);
+               get.setMaxWidth(Double.MAX_VALUE);
+               drop.setMaxWidth(Double.MAX_VALUE);
+               connect.setMaxWidth(Double.MAX_VALUE);
+               merchant.setMaxWidth(Double.MAX_VALUE);
+               equipment.setMaxWidth(Double.MAX_VALUE);
+               quit.setMaxWidth(Double.MAX_VALUE);
+
+               BorderPane lower = new BorderPane();
+               main.setBottom(lower);
+
+               lower.setTop(cmdLine = new TextField());
+               lower.setBottom(log = new TextArea());
+
+               // Events
+               cmdLine.setOnKeyPressed(keyPressed);
+               layers.setOnKeyPressed(keyPressed);
+               layers.setOnMouseClicked(mouseClicked);
+
+               merchant.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
+                       public void handle(javafx.event.ActionEvent t) {
+                               game.merchant();
+                       }
+               });
+               quit.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
+                       public void handle(javafx.event.ActionEvent t) {
+                               game.quit();
+                       }
+               });
+               equipment.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
+                       public void handle(javafx.event.ActionEvent t) {
+                               game.equipment();
+                       }
+               });
+               connect.setOnAction(new EventHandler<javafx.event.ActionEvent>() {
+                       public void handle(javafx.event.ActionEvent t) {
+                               //userconnect();
+                       }
+               });
+       }
+       Random rand = new Random();
+
+       public void damageEntity(Entity e, double direction, double x, double y, int delta, String what) {
+               final Label node = new Label(String.format("%s %+d", what, delta));
+
+               if (delta <= 0) {
+                       node.setId("damage-bubble");
+               } else {
+                       node.setId("health-bubble");
+               }
+               node.relocate(x, y);
+
+               Duration dur = Duration.millis(1500);
+               // Fade out
+               Transition fade =
+                               FadeTransitionBuilder.create().node(node)
+                               .duration(dur)
+                               .interpolator(Interpolator.EASE_IN)
+                               .fromValue(1)
+                               .toValue(0)
+                               .onFinished(new EventHandler<ActionEvent>() {
+                       @Override
+                       public void handle(ActionEvent t) {
+                               battle.getChildren().remove(node);
+                       }
+               }).build();
+
+               // animate randomly away from centre
+               double a = rand.nextDouble() * Math.PI * 0.75 + direction - Math.PI * 0.375;
+
+               //a = direction;
+
+               double radius = 32;
+               double sx = Math.cos(a) * radius / 2;
+               double sy = Math.sin(a) * radius / 2;
+               double ex = Math.cos(a) * radius + sx;
+               double ey = Math.sin(a) * radius + sy;
+
+               Transition move =
+                               TranslateTransitionBuilder.create().node(node)
+                               .duration(dur)
+                               .interpolator(Interpolator.EASE_OUT)
+                               .fromX(sx).fromY(sy)
+                               .toX(ex).toY(ey)
+                               .build();
+
+               final Transition t = new ParallelTransition(fade, move);
+
+               // Quick and dirty 'damage' popup
+               Platform.runLater(new Runnable() {
+                       @Override
+                       public void run() {
+                               battle.getChildren().add(node);
+
+                               t.play();
+                       }
+               });
+       }
+       Bookmarks bm;
+       GridPane loginPane;
+       ListView<Bookmarks.Bookmark> marks;
+       TextField host;
+       TextField port;
+       TextField user;
+       TextField pass;
+
+       public void showLogin() {
+               if (loginPane != null) {
+                       return;
+               }
+
+               loginPane = new GridPane();
+               loginPane.setId("login-window");
+               loginPane.setPrefSize(320, 200);
+               loginPane.setMaxSize(500, 300);
+               StackPane.setAlignment(loginPane, Pos.CENTER);
+
+               bm = new Bookmarks();
+               try {
+                       bm.load("bookmarks");
+               } catch (FileNotFoundException x) {
+               } catch (IOException ex) {
+                       Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex);
+               }
+
+               marks = new ListView<>();
+
+               marks.getItems().setAll(bm.getBookmarks());
+               Label l;
+               Insets li = new Insets(4, 8, 4, 8);
+               loginPane.add(marks, 0, 0, 1, 7);
+
+               loginPane.add(l = new Label("Host"), 1, 0);
+               GridPane.setMargin(l, li);
+               loginPane.add(host = new TextField(), 2, 0);
+               loginPane.add(l = new Label("Port"), 1, 1);
+               GridPane.setMargin(l, li);
+               loginPane.add(port = new TextField(), 2, 1);
+
+               GridPane.setHgrow(host, Priority.ALWAYS);
+               GridPane.setHgrow(port, Priority.ALWAYS);
+
+               Separator empty = new Separator();
+               GridPane.setVgrow(empty, Priority.ALWAYS);
+               loginPane.add(empty, 1, 2, 2, 1);
+
+               HBox hbox;
+               loginPane.add(hbox = new HBox(), 1, 3, 2, 1);
+               hbox.setAlignment(Pos.CENTER);
+               //GridPane.setHalignment(hbox, HPos.CENTER);
+               Button add = new Button("Add");
+               Button remove = new Button("Remove");
+
+               hbox.getChildren().addAll(add, remove);
+
+               loginPane.add(l = new Label("User"), 1, 4);
+               GridPane.setMargin(l, li);
+               loginPane.add(user = new TextField(), 2, 4);
+               loginPane.add(l = new Label("Pass"), 1, 5);
+               GridPane.setMargin(l, li);
+               loginPane.add(pass = new PasswordField(), 2, 5);
+
+               Button login = new Button("Connect");
+
+               GridPane.setValignment(login, VPos.BOTTOM);
+               GridPane.setHalignment(login, HPos.CENTER);
+               loginPane.add(login, 1, 6, 2, 1);
+
+
+               GridPane.setVgrow(hbox, Priority.NEVER);
+               GridPane.setVgrow(login, Priority.NEVER);
+
+               bm.setBookmarks(marks.getItems());
+
+               marks.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Bookmarks.Bookmark>() {
+                       public void changed(ObservableValue<? extends Bookmarks.Bookmark> ov, Bookmarks.Bookmark t, Bookmarks.Bookmark t1) {
+                               host.setText(t1.host);
+                               port.setText(Integer.toString(t1.port));
+                       }
+               });
+
+               add.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               try {
+                                       marks.getItems().add(new Bookmarks.Bookmark(host.getText(), Integer.valueOf(port.getText())));
+                                       bm.save("bookmarks");
+                               } catch (NumberFormatException x) {
+                               } catch (IOException x) {
+                               }
+                       }
+               });
+
+               remove.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               int i = marks.getSelectionModel().getSelectedIndex();
+                               try {
+
+                                       if (i != -1) {
+                                               marks.getItems().remove(i);
+                                               bm.save("bookmarks");
+                                       }
+                               } catch (IOException ex) {
+                                       Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex);
+                               }
+                       }
+               });
+
+               login.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               System.out.println("logging in!");
+                               game.connect(host.getText(), Integer.valueOf(port.getText()), user.getText(), pass.getText());
+                       }
+               });
+
+               loginPane.setOpacity(0);
+               getChildren().add(loginPane);
+
+               FadeTransition anim = new FadeTransition(Duration.millis(250), loginPane);
+               anim.setFromValue(0);
+               anim.setToValue(1);
+               anim.play();
+       }
+
+       public void loginFailed() {
+               // display somewhere?
+       }
+
+       public void loginOk() {
+               if (loginPane != null) {
+                       closeWindow(loginPane);
+                       loginPane = null;
+               }
+       }
+
+       void closeWindow(final Pane window) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               main.setEffect(null);
+                               if (true) {
+                                       final FadeTransition anim = new FadeTransition(Duration.millis(250), window);
+
+                                       anim.setFromValue(1);
+                                       anim.setToValue(0);
+                                       anim.setOnFinished(new EventHandler<ActionEvent>() {
+                                               public void handle(ActionEvent t) {
+                                                       getChildren().remove(anim.getNode());
+                                               }
+                                       });
+                                       anim.play();
+                               } else {
+                                       getChildren().remove(window);
+                               }
+                       }
+               });
+       }
+       GridPane racePane;
+       ListView<String> raceList;
+
+       public void chooseRace(String prompt, List<String> races) {
+               if (racePane != null) {
+                       return;
+               }
+
+               racePane = new GridPane();
+               racePane.setId("race-window");
+               racePane.setMaxSize(500, 300);
+               StackPane.setAlignment(racePane, Pos.CENTER);
+
+               raceList = new ListView<>();
+               raceList.getItems().setAll(races);
+
+               racePane.add(new Label(prompt), 0, 0);
+
+               racePane.add(raceList, 0, 1);
+
+               Button ok = new Button("Ok");
+
+               racePane.add(ok, 0, 2);
+
+               ok.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               String item = raceList.getSelectionModel().getSelectedItem();
+                               if (item != null) {
+                                       getChildren().remove(racePane);
+                                       racePane = null;
+                                       game.chooseRace(item);
+                               }
+                       }
+               });
+
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               getChildren().add(racePane);
+                       }
+               });
+
+       }
+       /**
+        * Need to know about merchant changes so track them here.
+        */
+       VBox shopPane;
+       TransactionPane buyPane;
+       TransactionPane sellPane;
+
+       public void setBuyList(final List<TransactionItem> buyList) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               if (shopPane != null) {
+                                       buyPane.setItems(buyList);
+                               }
+                               merchant.setDisable(false);
+                       }
+               });
+       }
+
+       public void setSellList(final List<TransactionItem> sellList) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               if (shopPane != null) {
+                                       sellPane.setItems(sellList);
+                               }
+                               merchant.setDisable(false);
+                       }
+               });
+       }
+
+       @Override
+       public void exitShop() {
+               merchant.setDisable(!false);
+               if (shopPane != null) {
+                       closeWindow(shopPane);
+                       shopPane = null;
+               }
+       }
+
+       @Override
+       public void enterShop(String title, final List<TransactionItem> buyList, final List<TransactionItem> sellList) {
+               if (shopPane != null) {
+                       // update items?
+                       Platform.runLater(new Runnable() {
+                               public void run() {
+                                       buyPane.setItems(buyList);
+                                       sellPane.setItems(sellList);
+                               }
+                       });
+
+                       return;
+               }
+
+               shopPane = new VBox();
+               shopPane.setId("shop-window");
+               shopPane.setMaxSize(600, 400);
+               StackPane.setAlignment(shopPane, Pos.CENTER);
+
+               TabPane tabs = new TabPane();
+
+               Tab tab = new Tab("Buy");
+               Button b;
+
+               buyPane = new TransactionPane(b = new Button("Buy"));
+               tab.setContent(buyPane);
+               tab.setClosable(false);
+               tabs.getTabs().add(tab);
+
+               b.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               game.buy(buyPane.getItem(), buyPane.getQuantity());
+                       }
+               });
+
+               tab = new Tab("Sell");
+               sellPane = new TransactionPane(b = new Button("Sell"));
+               tab.setContent(sellPane);
+               tab.setClosable(false);
+               tabs.getTabs().add(tab);
+
+               b.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               game.sell(sellPane.getItem(), sellPane.getQuantity());
+                       }
+               });
+
+               Label head = new Label(title);
+               head.setId("window-title");
+               head.setAlignment(Pos.BASELINE_LEFT);
+
+               buyPane.setItems(buyList);
+               sellPane.setItems(sellList);
+
+               Button tail = new Button("Leave");
+
+               tail.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               closeWindow(shopPane);
+                               shopPane = null;
+                       }
+               });
+
+               shopPane.setAlignment(Pos.CENTER);
+               shopPane.getChildren().addAll(head, tabs, tail);
+
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               main.setEffect(new BoxBlur(3, 3, 2));
+                               getChildren().add(shopPane);
+                       }
+               });
+       }
+       VBox equipWindow;
+       EquipmentPane equip;
+
+       @Override
+       public void manageEquipment(Equipment worn) {
+               if (equipWindow != null) {
+                       equip.setEquipment(worn);
+                       return;
+               }
+
+               equipWindow = new VBox();
+               equipWindow.setId("shop-window");
+               equipWindow.setMaxSize(600, 400);
+               StackPane.setAlignment(equipWindow, Pos.CENTER);
+
+               equip = new EquipmentPane();
+
+               Label head = new Label("Equipment");
+               head.setId("window-title");
+               head.setAlignment(Pos.BASELINE_LEFT);
+
+               equip.setEquipment(worn);
+
+               Button tail = new Button("Return");
+
+               tail.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               closeWindow(equipWindow);
+                               equipWindow = null;
+                       }
+               });
+
+               equipWindow.setAlignment(Pos.CENTER);
+               equipWindow.getChildren().addAll(head, equip, tail);
+
+               equip.wear.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               game.wear(equip.getItem().name);
+                       }
+               });
+               equip.unwear.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               EquipmentPane.ItemInfo ii = equip.getItem();
+                               game.unwear(Equipment.names[ii.wornAt]);
+                       }
+               });
+               equip.drop.setOnAction(new EventHandler<ActionEvent>() {
+                       public void handle(ActionEvent t) {
+                               game.drop(equip.getItem().name);
+                       }
+               });
+
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               main.setEffect(new BoxBlur(3, 3, 2));
+                               getChildren().add(equipWindow);
+                       }
+               });
+
+
+       }
+
+       /**
+        * For closing poup windows that can be closed
+        */
+       public void exitWindow() {
+               if (shopPane != null) {
+                       closeWindow(shopPane);
+                       shopPane = null;
+               }
+       }
+
+       @Override
+       public void visitFile(String file, String text, boolean canSave) {
+               throw new UnsupportedOperationException("Not supported yet.");
+               // FIXME: implement edit text, 
+               // FIXME: sent using: appParent.outstream.writeBytes("submit "+strName+"\n");
+               //                    appParent.outstream.writeBytes(txtEdit.getText()+"\n--EOF--\n");
+       }
+       //Accept key input
+       EventHandler<javafx.scene.input.KeyEvent> keyPressed = new EventHandler<javafx.scene.input.KeyEvent>() {
+               @Override
+               public void handle(javafx.scene.input.KeyEvent evt) {
+                       if (!game.isConnected()) {
+                               return;
+                       }
+
+                       KeyCode nkey = evt.getCode();
+                       if (nkey == KeyCode.ENTER) {
+                               String cmd = cmdLine.getText();
+                               //Thanks to Joe Alloway for this addition
+                               if (cmd.startsWith("!")) {
+                                       if (cmd.length() == 1) {
+                                               postMove = null;
+                                       } else {
+                                               postMove = cmd.substring(1);
+                                       }
+                               } else {
+                                       game.command(cmd);
+                               }
+                               //End contribution by Joe Alloway
+                               cmdLine.setText("");
+                       }
+                       if (game.isLoaded()) {
+                               Direction dir = null;
+                               switch (nkey) {
+                                       case UP:
+                                               dir = Direction.North;
+                                               break;
+                                       case DOWN:
+                                               dir = Direction.South;
+                                               break;
+                                       case LEFT:
+                                               dir = Direction.West;
+                                               break;
+                                       case RIGHT:
+                                               dir = Direction.East;
+                                               break;
+                               }
+                               if (dir != null) {
+                                       game.move(dir);
+                                       if (postMove != null)
+                                               game.command(postMove);
+                               }
+                       }
+               }
+       };
+       EventHandler<javafx.scene.input.MouseEvent> mouseClicked = new EventHandler<javafx.scene.input.MouseEvent>() {
+               @Override
+               public void handle(javafx.scene.input.MouseEvent evt) {
+                       System.out.println("Mouse clicked: " + evt);
+                       if (!game.isConnected() || !game.isLoaded()) {
+                               return;
+                       }
+
+                       /**
+                        * Map coordinates to screen-relative tiles and pass to game.
+                        */
+                       int x = (int) evt.getX();
+                       int y = (int) evt.getY();
+                       int destX = (x / game.getTileSize()) + game.getMapOffsetX();
+                       int destY = (y / game.getTileSize()) + game.getMapOffsetY();
+
+                       game.moveTo(destX, destY);
+                       cmdLine.requestFocus();
+               }
+       };
+       EventHandler<ActionEvent> attackHandler = new EventHandler<ActionEvent>() {
+               public void handle(ActionEvent t) {
+                       game.attack((Entity) ((MenuItem) t.getSource()).getUserData());
+               }
+       };
+       EventHandler<ActionEvent> lookHandler = new EventHandler<ActionEvent>() {
+               public void handle(ActionEvent t) {
+                       game.look((Entity) ((MenuItem) t.getSource()).getUserData());
+               }
+       };
+       EventHandler<ActionEvent> actionHandler = new EventHandler<ActionEvent>() {
+               public void handle(ActionEvent t) {
+                       MenuItem mi = (MenuItem) t.getSource();
+                       game.command(mi.getText());
+               }
+       };
+       EventHandler<ActionEvent> getHandler = new EventHandler<ActionEvent>() {
+               public void handle(ActionEvent t) {
+                       game.take((Entity) ((MenuItem) t.getSource()).getUserData());
+               }
+       };
+       EventHandler<ActionEvent> dropHandler = new EventHandler<ActionEvent>() {
+               public void handle(ActionEvent t) {
+                       game.drop(((MenuItem) t.getSource()).getText());
+               }
+       };
+
+       @Override
+       public void logClear() {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               log.setText("");
+                       }
+               });
+       }
+
+       @Override
+       public GUI log(String txt, Object... args) {
+               final String s = String.format(txt, args);
+
+               Platform.runLater(new Runnable() {
+                       public void run() {
+
+                               // Truncate history
+                               if (log.textProperty().getValueSafe().length() > 8000) {
+                                       log.deleteText(0, 4000);
+                               }
+
+                               log.appendText(s);
+                       }
+               });
+               return this;
+       }
+
+       void setStringMenu(final MenuButton menu, List<String> list, EventHandler<ActionEvent> handle) {
+               final List<MenuItem> items = new ArrayList<>();
+               MenuItemBuilder mib = MenuItemBuilder.create().onAction(handle);
+
+               for (String e : list) {
+                       items.add(mib.text(e).build());
+               }
+               Platform.runLater(new Runnable() {
+                       @Override
+                       public void run() {
+                               menu.getItems().setAll(items);
+                       }
+               });
+       }
+
+       void setEntityMenu(final MenuButton menu, List<Entity> list, EventHandler<ActionEvent> handle) {
+               final List<MenuItem> items = new ArrayList<>();
+               MenuItemBuilder mib = MenuItemBuilder.create().onAction(handle);
+
+               for (Entity e : list) {
+                       items.add(mib.userData(e).text(e.getIndexedName()).build());
+               }
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               menu.getItems().setAll(items);
+                       }
+               });
+       }
+
+       @Override
+       public void setDropList(List<String> drops) {
+               setStringMenu(drop, drops, dropHandler);
+       }
+
+       @Override
+       public void setAttackList(List<Entity> list) {
+               setEntityMenu(attack, list, attackHandler);
+       }
+
+       @Override
+       public void setTakeList(List<Entity> list) {
+               setEntityMenu(get, list, getHandler);
+       }
+
+       @Override
+       public void setLookList(List<Entity> list) {
+               setEntityMenu(look, list, lookHandler);
+       }
+
+       @Override
+       public void setActionList(List<String> list) {
+               setStringMenu(action, list, actionHandler);
+       }
+
+       @Override
+       public void setStats(final String stats) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               MainFrameFX.this.stats.setText(stats);
+                       }
+               });
+       }
+
+       @Override
+       public void setStatus(final Status status) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               info.setText(status.toString());
+                       }
+               });
+       }
+
+       @Override
+       public void setEquipment(final Equipment worn) {
+               Platform.runLater(new Runnable() {
+                       public void run() {
+                               if (equipWindow != null) {
+                                       equip.setEquipment(worn);
+                               }
+                       }
+               });
+       }
+       //DataManagerFX data;
+       Image tileImage;
+       int tileSize;
+       Image playerImage;
+       int playerSize;
+       Image spriteImage;
+       int spriteSize;
+
+       @Override
+       public void setImages(String tiles, int tileSize, String players, int playerSize, String sprites, int spriteSize) {
+               //try {
+               System.out.println("set tile image");
+               // FIXME: put sprites into data manager
+               //data = new DataManagerFX("/home/notzed/house.jar");
+               //data.open();
+               tileImage = new Image(tiles, false);
+               this.tileSize = tileSize;
+               playerImage = new Image(players, false);
+               this.playerSize = playerSize;
+               spriteImage = new Image(sprites, false);
+               this.spriteSize = spriteSize;
+               //} catch (IOException ex) {
+               //      Logger.getLogger(MainFrameFX.class.getName()).log(Level.SEVERE, null, ex);
+               //}
+       }
+
+       @Override
+       public void updateMap(ClientMap map) {
+               // First ugly cut - just create a whole set of tiles
+               System.out.println("update map");
+               //if (data == null) {
+               if (tileImage == null) {
+                       System.out.println("Map not ready yet");
+                       return;
+               }
+
+               final ArrayList<Node> children = new ArrayList<>();
+               final ArrayList<Node> upper = new ArrayList<>();
+
+               // Build map
+               for (int y = 0; y < map.rows; y++) {
+                       for (int x = 0; x < map.cols; x++) {
+                               ImageView iv = new ImageView(tileImage);
+                               int tileid = map.getTile(x, y);
+                               iv.setViewport(new Rectangle2D(tileid * tileSize, 0, tileSize, tileSize));
+                               iv.relocate(x * tileSize, y * tileSize);
+                               children.add(iv);
+
+                               //children.add(data.createTile(map.getTile(x, y), x, y, tileSize, tileSize));
+
+                               // TODO: names always? on top
+                               Collection<Entity> ents = map.getEntities(x + map.offx, y + map.offy);
+                               if (ents != null) {
+                                       for (Entity e : ents) {
+                                               drawEntity(e, map.offx, map.offy, children, upper);
+                                       }
+                               }
+                       }
+               }
+
+               // Build sprites
+               //for (Entity e : map.getEntities()) {
+               //      drawEntity(map.offx, map.offy, children, e);
+               //}
+
+               Platform.runLater(new Runnable() {
+                       @Override
+                       public void run() {
+                               graphics.getChildren().setAll(children);
+                               graphics.getChildren().addAll(upper);
+                       }
+               });
+       }
+       DropShadow textShadow = new DropShadow(3, 2, 2, Color.BLACK);
+
+       // HACK: upper is used for 'upper layer', stuff drawn afterwards
+       void drawEntity(Entity e, int offx, int offy, ArrayList<Node> children, ArrayList<Node> upper) {
+               double x = e.locx - offx;
+               double y = e.locy - offy;
+
+               // TODO: just make it an entity node
+
+               if (e.intStep == -1) {
+                       // Hack: sprites are 64x64
+                       ImageView iv = new ImageView(spriteImage);
+                       iv.setViewport(new Rectangle2D(e.intImage * spriteSize, 0,
+                                       spriteSize, spriteSize));
+                       iv.relocate((x * tileSize) - tileSize / 2, (y * tileSize) - tileSize / 2);
+                       iv.setScaleX(0.5);
+                       iv.setScaleY(0.5);
+                       children.add(iv);
+
+               } else {
+                       ImageView iv = new ImageView(playerImage);
+                       iv.setViewport(new Rectangle2D((e.intImage * 8 + e.intStep) * spriteSize, 0,
+                                       spriteSize, spriteSize));
+                       iv.relocate((x * tileSize) - tileSize / 2, (y * tileSize) - tileSize / 2);
+                       iv.setScaleX(0.5);
+                       iv.setScaleY(0.5);
+                       children.add(iv);
+               }
+               if (e.intNum == 0) {
+                       Text t = new Text(e.strName);
+                       t.setId("entity-label");
+                       t.relocate((x * tileSize) + tileSize / 2 - t.getLayoutBounds().getWidth() / 2, ((y + 1) * tileSize));
+                       upper.add(t);
+               } else {
+                       Text t = new Text(e.intNum + "." + e.strName);
+                       t.setId("entity-label");
+                       t.relocate((x * tileSize) + tileSize / 2 - t.getLayoutBounds().getWidth() / 2, ((y + 1) * tileSize));
+                       upper.add(t);
+               }
+               //Draw flag
+               if (e.intFlag != 0) {
+                       Rectangle r = new Rectangle(1, 1, tileSize - 2, tileSize - 2);
+                       if (e.intFlag == 1) {
+                               r.setStroke(Color.GREEN);
+                       } else if (e.intFlag == 2) {
+                               r.setStroke(Color.RED);
+                       }
+                       r.setStrokeWidth(2);
+                       r.setArcHeight(12);
+                       r.setArcWidth(12);
+                       r.setFill(null);
+                       r.relocate(x * tileSize, y * tileSize);
+                       upper.add(r);
+               }
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/TransactionPane.java b/DuskZ/src/duskz/client/fx/TransactionPane.java
new file mode 100644 (file)
index 0000000..733bdf9
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * This file is part of DuskZ, a graphical mud engine.
+ *
+ * Copyright (C) 2013 Michael Zucchi <notzed@gmail.com>
+ *
+ * DuskZ is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * DuskZ is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with DuskZ.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/**
+ * Changes
+ */
+package duskz.client.fx;
+
+import duskz.client.TransactionItem;
+import java.util.List;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TableColumn;
+import javafx.scene.control.TableView;
+import javafx.scene.control.cell.PropertyValueFactory;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.VBox;
+import jfxtras.labs.scene.control.ListSpinner;
+
+/**
+ *
+ * @author notzed
+ */
+public class TransactionPane extends HBox {
+
+       TableView<TransactionItem> table;
+       Label detail;
+       ListSpinner quantity;
+       Button action;
+
+       public TransactionPane(Button action) {
+               this.action = action;
+
+               setId("buy-pane");
+
+               VBox right = new VBox();
+
+               HBox.setHgrow(right, Priority.ALWAYS);
+
+               right.setAlignment(Pos.TOP_RIGHT);
+               right.setFillWidth(true);
+
+               table = new TableView<>();
+               detail = new Label();
+               quantity = new ListSpinner(1, 100);
+
+               HBox hb;
+
+               hb = new HBox();
+               hb.setFillHeight(true);
+               VBox.setVgrow(hb, Priority.ALWAYS);
+               hb.getChildren().add(detail);
+               right.getChildren().add(hb);
+
+               hb = new HBox();
+               hb.getChildren().add(quantity);
+               hb.getChildren().add(new Label("Quantity:"));
+               hb.setAlignment(Pos.CENTER);
+               right.getChildren().add(hb);
+
+               //      hb = new HBox();
+               //      hb.getChildren().add(action);
+               //      hb.setAlignment(Pos.BOTTOM_RIGHT);
+               //      right.getChildren().add(hb);
+               right.getChildren().add(action);
+
+               HBox.setHgrow(table, Priority.NEVER);
+
+               getChildren().addAll(table, right);
+
+
+               TableColumn<TransactionItem, String> countCol = new TableColumn<TransactionItem, String>("Count");
+               countCol.setCellValueFactory(new PropertyValueFactory("count"));
+
+               TableColumn<TransactionItem, String> nameCol = new TableColumn<TransactionItem, String>("Name");
+               nameCol.setCellValueFactory(new PropertyValueFactory("name"));
+
+               TableColumn<TransactionItem, String> costCol = new TableColumn<TransactionItem, String>("Cost");
+               costCol.setCellValueFactory(new PropertyValueFactory("cost"));
+
+               table.getColumns().setAll(countCol, nameCol, costCol);
+
+               countCol.setMinWidth(50);
+               nameCol.setMinWidth(180);
+               costCol.setMinWidth(50);
+               table.setMinWidth(310);
+               table.setMaxWidth(310);
+
+               countCol.setResizable(false);
+               nameCol.setResizable(false);
+               costCol.setResizable(false);
+               table.setEditable(false);
+
+               table.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TransactionItem>() {
+                       @Override
+                       public void changed(ObservableValue<? extends TransactionItem> ov, TransactionItem t, TransactionItem t1) {
+                               if (t1 != null) {
+                                       detail.setText(String.format("Item: %s\nCost: %s\n\n ... some description or shit ...\n",
+                                                       t1.name, t1.cost));
+                               } else {
+                                       detail.setText("");
+                               }
+                       }
+               });
+       }
+
+       public int getQuantity() {
+               return ((Number) quantity.getValue()).intValue();
+       }
+
+       public TransactionItem getItem() {
+               return table.getSelectionModel().getSelectedItem();
+       }
+
+       public void setItems(List<TransactionItem> items) {
+               this.table.getItems().setAll(items);
+       }
+}
diff --git a/DuskZ/src/duskz/client/fx/style.css b/DuskZ/src/duskz/client/fx/style.css
new file mode 100644 (file)
index 0000000..c81c59b
--- /dev/null
@@ -0,0 +1,85 @@
+/* 
+    Document   : style
+    Created on : 21/02/2013, 11:27:00 AM
+    Author     : notzed
+    Description: A very ugly stylesheet just waiting for a graphical designer
+               to improve it.
+*/
+
+.scene {
+       /* global palette */
+       enitity-background: rgba(1,1,0.5,0.25);
+}
+.button {
+    -fx-background-color:
+        #c3c4c4,
+        linear-gradient(#d6d6d6 50%, white 100%),
+        radial-gradient(center 50% -40%, radius 200%, #e6e6e6 45%, rgba(230,230,230,0) 50%);
+       /*   -fx-background-radius: 30;*/
+    -fx-background-insets: 0,1,1;
+    -fx-text-fill: black;
+    -fx-effect: dropshadow( three-pass-box , rgba(0,0,0,0.6) , 3, 0.0 , 0 , 1 );
+}
+
+#login-window, #race-window, #shop-window {
+    -fx-padding: 10;
+       -fx-border-color: #000000;
+       -fx-border-radius: 12;
+       -fx-background-radius: 12;
+    -fx-background-color:
+        linear-gradient(to bottom right, antiquewhite, maroon);
+}
+
+#entity-label {
+       -fx-font-family: 'sans';
+       -fx-font-size: small;   
+       -fx-font-weight: bold;
+       -fx-fill: white;
+       -fx-effect: dropshadow(one-pass-box, black, 4, 0, 2, 2);
+}
+#window-title {
+       -fx-font-family: 'serif';
+       -fx-font-size: x-large;
+}
+.tab-pane {
+       -fx-tab-min-width: 250px;
+}
+
+.tab-header-area {
+       -fx-alignment: center;
+}
+
+#shop-window .table-view {
+    -fx-padding: 5px;
+}
+#shop-window .table-cell {
+       -fx-font-size: small;
+       -fx-padding: 0px;
+}
+
+.table-row-cell, .list-cell {
+       -fx-background-color: lemonchiffon;     
+}
+.table-row-cell:selected, .list-cell:selected {
+       -fx-background-color: burlywood;        
+}
+#shop-window .label {
+       -fx-padding: 5px;
+}
+#health-bubble, #damage-bubble {
+    -fx-background-radius: 20;
+    -fx-background-insets: 0;
+    -fx-text-fill: black;
+       -fx-padding: 4;
+}
+
+#health-bubble {
+    -fx-background-color:  #33c333,
+        linear-gradient(#33c333 50%, white 100%),
+        radial-gradient(center 50% -40%, radius 200%, #e6e6e6 45%, rgba(230,230,230,0) 50%);
+}
+#damage-bubble {
+    -fx-background-color:  #c33333,
+        linear-gradient(#c33333 50%, white 100%),
+        radial-gradient(center 50% -40%, radius 200%, #e6e6e6 45%, rgba(230,230,230,0) 50%);
+}
diff --git a/DuskZ/src/jfxtras/labs/animation/Timer.java b/DuskZ/src/jfxtras/labs/animation/Timer.java
new file mode 100644 (file)
index 0000000..f7a56fd
--- /dev/null
@@ -0,0 +1,155 @@
+/**
+ * Copyright (c) 2011, JFXtras
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the <organization> nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jfxtras.labs.animation;
+
+import java.util.TimerTask;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javafx.application.Platform;
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.util.Duration;
+
+/**
+ * A timer class in the spirit of java.swing.Timer but using JavaFX properties.
+ * 
+ * @author Tom Eugelink
+ *
+ */
+public class Timer
+{
+       // ==================================================================================================================
+       // CONSTRUCTOR
+       
+       /**
+        * 
+        * @param runnable
+        */
+       public Timer(Runnable runnable)
+       {
+               this(true, runnable);
+       }
+       
+       /**
+        * 
+        * @param isDaemon
+        * @param runnable
+        */
+       public Timer(boolean isDaemon, final Runnable runnable)
+       {
+               this.runnable = runnable;
+               timer = new java.util.Timer(isDaemon);
+       }
+       final private Runnable runnable;
+       final private java.util.Timer timer;
+       
+       // ==================================================================================================================
+       // PROPERTIES
+       
+       /** delay: initial delay */
+       public ObjectProperty<Duration> delayProperty() { return this.delayObjectProperty; }
+       final private ObjectProperty<Duration> delayObjectProperty = new SimpleObjectProperty<Duration>(this, "delay", Duration.millis(0));
+       public Duration getDelay() { return this.delayObjectProperty.getValue(); }
+       public void setDelay(Duration value) { this.delayObjectProperty.setValue(value); }
+       public Timer withDelay(Duration value) { setDelay(value); return this; }
+       
+       /** cycleDuration: time between fires */
+       public ObjectProperty<Duration> cycleDurationProperty() { return this.cycleDurationObjectProperty; }
+       final private ObjectProperty<Duration> cycleDurationObjectProperty = new SimpleObjectProperty<Duration>(this, "cycleDuration", Duration.millis(1000));
+       public Duration getCycleDuration() { return this.cycleDurationObjectProperty.getValue(); }
+       public void setCycleDuration(Duration value) { this.cycleDurationObjectProperty.setValue(value); }
+       public Timer withCycleDuration(Duration value) { setCycleDuration(value); return this; }
+       
+       /** repeats: If flag is false, instructs the Timer to send only one action event to its listeners. */
+       public ObjectProperty<Boolean> repeatsProperty() { return this.repeatsObjectProperty; }
+       final private ObjectProperty<Boolean> repeatsObjectProperty = new SimpleObjectProperty<Boolean>(this, "repeats", Boolean.TRUE);
+       public boolean getRepeats() { return this.repeatsObjectProperty.getValue(); }
+       public void setRepeats(boolean value) { this.repeatsObjectProperty.setValue(value); }
+       public Timer withRepeats(boolean value) { setRepeats(value); return this; }
+       
+       
+       // ==================================================================================================================
+       // TIMER
+       
+       /**
+        * Start the timer
+        */
+       synchronized public Timer start()
+       {
+               // check if the timer is already running
+               if (timerTaskAtomicReference.get() != null) throw new IllegalStateException("Timer already started");
+               
+               // create a task and schedule it
+               final TimerTask lTimerTask = new TimerTask()
+               {
+                       @Override
+                       public void run()
+                       {
+                               Platform.runLater(runnable);
+                               if (repeatsObjectProperty.getValue().booleanValue() == false)
+                               {
+                                       stop();
+                               }
+                       }
+               };
+               timer.schedule(lTimerTask, (long)this.delayObjectProperty.getValue().toMillis(), (long)this.cycleDurationObjectProperty.getValue().toMillis());
+               
+               // remember for future reference
+               timerTaskAtomicReference.set(lTimerTask);
+               
+               // for chaining
+               return this;
+       }
+       final private AtomicReference<TimerTask> timerTaskAtomicReference = new AtomicReference<TimerTask>(null);
+       
+       /**
+        * stop the timer if running
+        */
+       public Timer stop()
+       {
+               TimerTask lTimerTask = timerTaskAtomicReference.getAndSet(null);
+               if (lTimerTask != null)
+               {
+                       lTimerTask.cancel();
+               }
+               
+               // for chaining
+               return this;
+       }
+       
+       /**
+        * restart the timer
+        */
+       public Timer restart()
+       {
+               stop();
+               start();
+               
+               // for chaining
+               return this;
+       }
+}
diff --git a/DuskZ/src/jfxtras/labs/internal/scene/control/ListSpinner.css b/DuskZ/src/jfxtras/labs/internal/scene/control/ListSpinner.css
new file mode 100644 (file)
index 0000000..cfeb60d
--- /dev/null
@@ -0,0 +1,47 @@
+/* basic settings */\r
+.ListSpinner { \r
+       -fx-skin: "jfxtras.labs.internal.scene.control.skin.ListSpinnerCaspianSkin";\r
+       -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;\r
+       -fx-background-insets: 0 0 -1 0, 0, 1, 2;\r
+       -fx-background-radius: 5, 5, 4, 3;\r
+       -fx-padding: 0.266667em 0.233333em 0.25em 0.233333em;\r
+       -fx-text-fill: -fx-text-base-color;\r
+}\r
+\r
+.ListSpinner:hover {\r
+    -fx-color: -fx-hover-base;\r
+}\r
+\r
+.ListSpinner:focused { \r
+       -fx-color: -fx-focused-base;\r
+       -fx-background-color: -fx-focus-color, -fx-outer-border, -fx-inner-border, -fx-body-color;\r
+       -fx-background-insets: -1.4, 0, 1, 2;\r
+       -fx-background-radius: 6.4, 5, 4, 3;    \r
+}\r
+\r
+.ListSpinner .value { \r
+       -fx-padding: 0.0em 0.2em 0.0em 0.2em;\r
+}\r
+\r
+.ListSpinner .left-arrow { \r
+    -fx-shape: "M4,-4 L0,0 L4,4 Z";\r
+    -fx-scale-shape: false;\r
+}\r
+.ListSpinner .right-arrow { \r
+    -fx-shape: "M0,-4 L4,0 L0,4 Z";\r
+    -fx-scale-shape: false;\r
+}\r
+.ListSpinner .down-arrow { \r
+    -fx-shape: "M-4,-2 L0,2 L4,-2 Z";\r
+    -fx-scale-shape: false;\r
+}\r
+.ListSpinner .up-arrow { \r
+    -fx-shape: "M4,2 L-4,2 L0,-2 Z";\r
+    -fx-scale-shape: false;\r
+}\r
+.ListSpinner .idle {\r
+    -fx-background-color: -fx-mark-color;\r
+}\r
+.ListSpinner .clicked { \r
+    -fx-background-color: -fx-focus-color;\r
+}\r
diff --git a/DuskZ/src/jfxtras/labs/internal/scene/control/behavior/ListSpinnerBehavior.java b/DuskZ/src/jfxtras/labs/internal/scene/control/behavior/ListSpinnerBehavior.java
new file mode 100644 (file)
index 0000000..99e6cf8
--- /dev/null
@@ -0,0 +1,167 @@
+/**
+ * Copyright (c) 2011, JFXtras
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the <organization> nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jfxtras.labs.internal.scene.control.behavior;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.MouseEvent;
+import javafx.util.Callback;
+import jfxtras.labs.scene.control.ListSpinner;
+
+import com.sun.javafx.scene.control.behavior.BehaviorBase;
+import com.sun.javafx.scene.control.behavior.KeyBinding;
+
+/**
+ * 
+ * @author Tom Eugelink
+ *
+ */
+public class ListSpinnerBehavior<T> extends BehaviorBase<ListSpinner<T>>
+{
+       // ==================================================================================================================
+       // CONSTRUCTOR
+       
+       /**
+        * 
+        * @param control
+        */
+       public ListSpinnerBehavior(ListSpinner<T> control)
+       {
+               super(control);
+               construct();
+       }
+       
+       /*
+        * 
+        */
+       private void construct()
+       {
+               
+       }
+
+       // ==================================================================================================================
+       // EDITABLE
+       
+       /**
+        * Parse the value (which usually comes from the TextField in the skin).
+        * If the value exists in the current items, select it.
+        * If not and a callback is defined, call the callback to have it handle it.
+        * Otherwise do nothing (leave it to the skin).
+        */
+       public void parse(String text)
+       {
+               // strip
+               String lText = text;
+               String lPostfix = getControl().getPostfix();
+               if (lPostfix.length() > 0 && lText.endsWith(lPostfix)) lText = lText.substring(0, lText.length() - lPostfix.length());
+               String lPrefix = getControl().getPrefix();
+               if (lPrefix.length() > 0 && lText.startsWith(lPrefix)) lText = lText.substring(lPrefix.length());
+               
+               // convert from string to value
+               T lValue = getControl().getStringConverter().fromString(lText);
+               
+               // if the value does exists in the domain
+               int lItemIndex = getControl().getItems().indexOf(lValue);
+               if (lItemIndex >= 0)
+               {
+                       // accept value and bail out
+                       getControl().setValue(lValue);
+                       return;
+               }
+               
+               // check to see if we have a addCallback
+               Callback<T, Integer> lAddCallback = getControl().getAddCallback();
+               if (lAddCallback != null)
+               {
+                       // call the callback
+                       Integer lIndex = lAddCallback.call(lValue);
+                       
+                       // if the callback reports that it has processed the value by returning the index where it has added the item. (Or at least the index it wants to show now.)
+                       if (lIndex != null)
+                       {
+                               // accept value and bail out
+                               getControl().setIndex(lIndex);
+                               return;
+                       }
+               }
+       }
+       
+       // ==================================================================================================================
+       // MOUSE EVENTS
+       
+       /**
+        * 
+        */
+       @Override public void mousePressed(MouseEvent evt)
+       {
+               // get the control
+               ListSpinner<T> lControl = getControl();
+               
+               // if a control does not have the focus, request focus
+               if (!lControl.isFocused() && lControl.isFocusTraversable()) {
+                       lControl.requestFocus();
+               }
+       }
+       
+       // ==================================================================================================================
+       // KEY EVENTS
+       
+       final static private String EVENT_PREVIOUS = "PreviousPressed";
+       final static private String EVENT_NEXT = "NextPressed";
+       protected final static List<KeyBinding> KEY_BINDINGS = new ArrayList<KeyBinding>();
+       static 
+       {
+               KEY_BINDINGS.add( new KeyBinding(KeyCode.MINUS, EVENT_PREVIOUS) ); // keyboard -                
+               KEY_BINDINGS.add( new KeyBinding(KeyCode.PLUS, EVENT_NEXT) ); // keyboard +
+               KEY_BINDINGS.add( new KeyBinding(KeyCode.SUBTRACT, EVENT_PREVIOUS) ); // keypad -               
+               KEY_BINDINGS.add( new KeyBinding(KeyCode.ADD, EVENT_NEXT) ); // keypad + 
+               KEY_BINDINGS.add(new KeyBinding(KeyCode.UP, EVENT_NEXT));
+               KEY_BINDINGS.add(new KeyBinding(KeyCode.DOWN, EVENT_PREVIOUS));
+               KEY_BINDINGS.add(new KeyBinding(KeyCode.LEFT, EVENT_PREVIOUS));
+               KEY_BINDINGS.add(new KeyBinding(KeyCode.RIGHT, EVENT_NEXT));
+               KEY_BINDINGS.addAll(TRAVERSAL_BINDINGS);
+       }
+       
+       @Override protected List<KeyBinding> createKeyBindings() 
+       {               
+               return KEY_BINDINGS;
+       }
+       
+       @Override protected void callAction(String name) {
+               if (EVENT_PREVIOUS.equals(name)) {
+                       getControl().decrement();
+               } 
+               else if (EVENT_NEXT.equals(name)) {
+                       getControl().increment();
+               } 
+               else {
+                       super.callAction(name);
+               }
+       }
+}
diff --git a/DuskZ/src/jfxtras/labs/internal/scene/control/skin/ListSpinnerCaspianSkin.java b/DuskZ/src/jfxtras/labs/internal/scene/control/skin/ListSpinnerCaspianSkin.java
new file mode 100644 (file)
index 0000000..4cb3b4e
--- /dev/null
@@ -0,0 +1,560 @@
+/**
+ * Copyright (c) 2011, JFXtras
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the <organization> nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jfxtras.labs.internal.scene.control.skin;
+
+import javafx.beans.InvalidationListener;
+import javafx.beans.Observable;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.event.ActionEvent;
+import javafx.event.EventHandler;
+import javafx.geometry.Point2D;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.TextField;
+import javafx.scene.input.KeyCode;
+import javafx.scene.input.KeyEvent;
+import javafx.scene.input.MouseEvent;
+import javafx.scene.input.ScrollEvent;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.ColumnConstraints;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.Region;
+import javafx.scene.layout.RowConstraints;
+import javafx.util.Duration;
+import jfxtras.labs.animation.Timer;
+import jfxtras.labs.internal.scene.control.behavior.ListSpinnerBehavior;
+import jfxtras.labs.scene.control.ListSpinner;
+import jfxtras.labs.scene.control.ListSpinner.ArrowDirection;
+import jfxtras.labs.scene.control.ListSpinner.ArrowPosition;
+
+import com.sun.javafx.scene.control.skin.SkinBase;
+
+/**
+ * 
+ * @author Tom Eugelink
+ * 
+ * Possible extension: drop down list or grid for quick selection
+ */
+public class ListSpinnerCaspianSkin<T> extends SkinBase<ListSpinner<T>, ListSpinnerBehavior<T>>
+{
+       // TODO: vertical centering 
+       
+       // ==================================================================================================================
+       // CONSTRUCTOR
+       
+       /**
+        * 
+        */
+       public ListSpinnerCaspianSkin(ListSpinner<T> control)
+       {
+               super(control, new ListSpinnerBehavior<T>(control));
+               construct();
+       }
+
+       /*
+        * 
+        */
+       private void construct()
+       {
+               // setup component
+               createNodes();
+               
+               // react to value changes in the model
+               getSkinnable().editableProperty().addListener(new ChangeListener<Boolean>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends Boolean> arg0, Boolean arg1, Boolean arg2)
+                       {
+                               replaceValueNode();
+                       }
+               });
+               replaceValueNode();
+               
+               // react to value changes in the model
+               getSkinnable().valueProperty().addListener(new ChangeListener<T>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends T> observableValue, T oldValue, T newValue)
+                       {
+                               refreshValue();
+                       }
+               });
+               refreshValue();
+               
+               // react to value changes in the model
+               getSkinnable().arrowDirectionProperty().addListener(new ChangeListener<ListSpinner.ArrowDirection>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends ArrowDirection> observableValue, ArrowDirection oldValue, ArrowDirection newValue)
+                       {
+                               setArrowCSS();
+                               layoutGridPane();
+                       }
+               });
+               setArrowCSS();
+               layoutGridPane();
+               
+               // react to value changes in the model
+               getSkinnable().alignmentProperty().addListener(new ChangeListener<Pos>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends Pos> observableValue, Pos oldValue, Pos newValue)
+                       {
+                               alignValue();
+                       }
+               });
+               alignValue();
+               
+       }
+       
+       /*
+        * 
+        */
+       private void refreshValue() 
+       {
+               // if editable
+               if (getSkinnable().isEditable() == true)
+               {
+                       // update textfield
+                       T lValue = getSkinnable().getValue();
+                       textField.setText( getSkinnable().getPrefix() + getSkinnable().getStringConverter().toString(lValue) + getSkinnable().getPostfix() );
+               }
+               else
+               {
+                       // get node for this value
+                       Node lNode = getSkinnable().getCellFactory().call( getSkinnable() );
+               }
+       }
+       
+       // ==================================================================================================================
+       // DRAW
+       
+       /**
+        * Construct the nodes. 
+        * Spinner uses a GridPane where the arrows and the node for the value are laid out according to the arrows direction and location.
+        * A place holder in inserted into the GridPane to hold the value node, so the spinner can alternate between editable or readonly mode, without having to recreate the GridPane.  
+        */
+       private void createNodes()
+       {
+               // left arrow
+               decrementArrow = new Region();
+               decrementArrow.getStyleClass().add("idle");
+
+               // place holder for showing the value
+               valueGroup = new BorderPane();
+               valueGroup.getStyleClass().add("valuePane");
+               
+               // right arrow
+               incrementArrow = new Region();
+               incrementArrow.getStyleClass().add("idle");
+
+               // construct a gridpane
+               gridPane = new GridPane();
+
+               // we're not catching the mouse events on the individual children, but let it bubble up to the parent and handle it there, this makes our life much more simple
+               // process mouse clicks
+               gridPane.setOnMouseClicked(new EventHandler<MouseEvent>()
+               {
+                       @Override public void handle(MouseEvent evt)
+                       {
+                               // if click was the in the greater vicinity of the decrement arrow
+                               if (mouseEventOverArrow(evt, decrementArrow))
+                               {
+                                       // left
+                                       unclickArrows();
+                                       decrementArrow.getStyleClass().add("clicked");
+                                       getSkinnable().decrement();
+                                       unclickTimer.restart();
+                                       return;
+                               }
+                               
+                               // if click was the in the greater vicinity of the increment arrow
+                               if (mouseEventOverArrow(evt, incrementArrow))
+                               {
+                                       // right
+                                       unclickArrows();
+                                       incrementArrow.getStyleClass().add("clicked");
+                                       getSkinnable().increment();
+                                       unclickTimer.restart();
+                                       return;
+                               }
+                       }
+               });
+               // process mouse holds
+               gridPane.setOnMousePressed(new EventHandler<MouseEvent>()
+               {
+                       @Override public void handle(MouseEvent evt)
+                       {
+                               // if click was the in the greater vicinity of the decrement arrow
+                               if (mouseEventOverArrow(evt, decrementArrow))
+                               {
+                                       // left
+                                       decrementArrow.getStyleClass().add("clicked");
+                                       repeatDecrementClickTimer.restart();
+                                       return;
+                               }
+                               
+                               // if click was the in the greater vicinity of the increment arrow
+                               if (mouseEventOverArrow(evt, incrementArrow))
+                               {
+                                       // right
+                                       incrementArrow.getStyleClass().add("clicked");
+                                       repeatIncrementClickTimer.restart();
+                                       return;
+                               }
+                       }
+               });
+               gridPane.setOnMouseReleased(new EventHandler<MouseEvent>()
+               {
+                       @Override public void handle(MouseEvent evt)
+                       {
+                               unclickArrows();
+                               repeatDecrementClickTimer.stop();
+                               repeatIncrementClickTimer.stop();
+                       }
+               });
+               gridPane.setOnMouseExited(new EventHandler<MouseEvent>()
+               {
+                       @Override public void handle(MouseEvent evt)
+                       {
+                               unclickArrows();
+                               repeatDecrementClickTimer.stop();
+                               repeatIncrementClickTimer.stop();
+                       }
+               });
+               // mouse wheel
+               gridPane.setOnScroll(new EventHandler<ScrollEvent>()
+               {
+                       @Override
+                       public void handle(ScrollEvent evt)
+                       {
+                               // if click was the in the greater vicinity of the decrement arrow
+                               if (evt.getDeltaY() < 0 || evt.getDeltaX() < 0)
+                               {
+                                       // left
+                                       unclickArrows();
+                                       decrementArrow.getStyleClass().add("clicked");
+                                       getSkinnable().decrement();
+                                       unclickTimer.restart();
+                                       return;
+                               }
+                               
+                               // if click was the in the greater vicinity of the increment arrow
+                               if (evt.getDeltaY() > 0 || evt.getDeltaX() > 0)
+                               {
+                                       // right
+                                       unclickArrows();
+                                       incrementArrow.getStyleClass().add("clicked");
+                                       getSkinnable().increment();
+                                       unclickTimer.restart();
+                                       return;
+                               }
+                       }
+               });
+               
+               // add to self
+               this.getStyleClass().add(this.getClass().getSimpleName()); // always add self as style class, because CSS should relate to the skin not the control
+               getChildren().add(gridPane); 
+       }
+       private Region decrementArrow = null;
+       private Region incrementArrow = null;
+       private GridPane gridPane = null;
+       private BorderPane valueGroup;
+       
+       // timer to remove the click styling on the arrows after a certain delay
+       final private Timer unclickTimer = new Timer(new Runnable()
+       {
+               @Override
+               public void run()
+               {
+                       unclickArrows();
+               }
+       }).withDelay(Duration.millis(100)).withRepeats(false);
+
+       // timer to handle the holding of the decrement button
+       final private Timer repeatDecrementClickTimer = new Timer(new Runnable()
+       {
+               @Override
+               public void run()
+               {
+                       getSkinnable().decrement();
+               }
+       }).withDelay(Duration.millis(500)).withCycleDuration(Duration.millis(50));
+       
+       // timer to handle the holding of the increment button
+       final private Timer repeatIncrementClickTimer = new Timer(new Runnable()
+       {
+               @Override
+               public void run()
+               {
+                       getSkinnable().increment();
+               }
+       }).withDelay(Duration.millis(500)).withCycleDuration(Duration.millis(50));
+
+       /**
+        * Check if the mouse event is considered to have happened over the arrow
+        * @param evt
+        * @param region
+        * @return
+        */
+       private boolean mouseEventOverArrow(MouseEvent evt, Region region)
+       {
+               // if click was the in the greater vicinity of the decrement arrow
+               Point2D lClickInRelationToArrow = region.sceneToLocal(evt.getSceneX(), evt.getSceneY());
+               if ( lClickInRelationToArrow.getX() >= 0.0 && lClickInRelationToArrow.getX() <= region.getWidth()
+                 && lClickInRelationToArrow.getY() >= 0.0 && lClickInRelationToArrow.getY() <= region.getHeight()
+                  )
+               {
+                       return true;
+               }
+               return false;
+       }
+       
+       /**
+        * Remove clicked CSS styling from the arrows
+        */
+       private void unclickArrows()
+       {
+               decrementArrow.getStyleClass().remove("clicked");
+               incrementArrow.getStyleClass().remove("clicked");
+       }
+       
+       /**
+        * Put the correct node for the value's place holder: 
+        * - either the TextField when in editable mode, 
+        * - or a node generated by the cell factory when in readonly mode.  
+        */
+       private void replaceValueNode()
+       {
+               // clear
+               valueGroup.getChildren().clear();
+               
+               // if not editable
+               if (getSkinnable().isEditable() == false)
+               {
+                       // use the cell factory
+                       Node lNode = getSkinnable().getCellFactory().call(getSkinnable());
+                       valueGroup.setCenter( lNode );
+                       if (lNode.getStyleClass().contains("value") == false) lNode.getStyleClass().add("value");
+                       if (lNode.getStyleClass().contains("readonly") == false) lNode.getStyleClass().add("readonly");
+               }
+               else
+               {
+                       // use the textfield
+                       if (textField == null) 
+                       {
+                               textField = new TextField();
+                               textField.getStyleClass().add("value");
+                               textField.getStyleClass().add("editable");
+                               
+                               // process text entry
+                               textField.focusedProperty().addListener(new InvalidationListener()
+                               {                       
+                                       @Override
+                                       public void invalidated(Observable arg0)
+                                       {
+                                               if (textField.isFocused() == false) 
+                                               {
+                                                       parse(textField);
+                                               }
+                                       }
+                               });
+                               textField.setOnAction(new EventHandler<ActionEvent>()
+                               {
+                                       @Override
+                                       public void handle(ActionEvent evt)
+                                       {
+                                               parse(textField);
+                                       }
+                               });
+                               textField.setOnKeyPressed(new EventHandler<KeyEvent>() 
+                               {
+                           @Override public void handle(KeyEvent t) 
+                           {
+                               if (t.getCode() == KeyCode.ESCAPE) 
+                               {
+                                               // refresh
+                                               refreshValue();
+                               }
+                           }
+                       });
+                               
+                               // alignment
+                               textField.alignmentProperty().bind(getSkinnable().alignmentProperty());
+                       }
+                       valueGroup.setCenter(textField);
+               }
+               
+               // align
+               alignValue();
+       }
+       private TextField textField = null;
+
+       /**
+        * align the value inside the plave holder
+        */
+       private void alignValue()
+       {
+               // valueGroup always only holds one child (the value)
+               BorderPane.setAlignment(valueGroup.getChildren().get(0), getSkinnable().alignmentProperty().getValue());
+       }
+       
+       // ==================================================================================================================
+       // EDITABLE
+       
+       /**
+        * Parse the contents of the textfield
+        * @param textField
+        */
+       protected void parse(TextField textField)
+       {
+               // get the text to parse
+               String lText = textField.getText();
+
+               // process it
+               getBehavior().parse(lText);
+               
+               // refresh
+               refreshValue();
+               return;
+       }
+       
+       /**
+        * Lays out the spinner, depending on the location and direction of the arrows.
+        */
+       private void layoutGridPane()
+       {
+               // get the things we decide on
+               ArrowDirection lArrowDirection = getSkinnable().getArrowDirection();
+               ArrowPosition lArrowPosition = getSkinnable().getArrowPosition();
+               
+               // get helper values
+               ColumnConstraints lColumnValue = new ColumnConstraints(valueGroup.getMinWidth(), valueGroup.getPrefWidth(), Double.MAX_VALUE);
+               lColumnValue.setHgrow(Priority.ALWAYS);
+               ColumnConstraints lColumnArrow = new ColumnConstraints(10);
+               
+               // get helper values
+               RowConstraints lRowValue = new RowConstraints(valueGroup.getMinHeight(), valueGroup.getPrefHeight(), Double.MAX_VALUE);
+               lRowValue.setVgrow(Priority.ALWAYS);
+               RowConstraints lRowArrow = new RowConstraints(10);
+
+               // clear the grid
+               gridPane.getChildren().clear();
+               gridPane.getColumnConstraints().clear();
+               gridPane.getRowConstraints().clear();
+               //gridPane.setGridLinesVisible(true);
+               
+               if (lArrowDirection == ArrowDirection.HORIZONTAL)
+               {
+                       if (lArrowPosition == ArrowPosition.LEADING)
+                       {
+                               // construct a gridpane: one row, three columns: arrow, arrow, value
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(decrementArrow, 0, 0);
+                               gridPane.add(incrementArrow, 1, 0);
+                               gridPane.add(valueGroup, 2, 0);
+                               gridPane.getColumnConstraints().addAll(lColumnArrow, lColumnArrow, lColumnValue);
+                       }
+                       if (lArrowPosition == ArrowPosition.TRAILING)
+                       {
+                               // construct a gridpane: one row, three columns: value, arrow, arrow
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(valueGroup, 0, 0);
+                               gridPane.add(decrementArrow, 1, 0);
+                               gridPane.add(incrementArrow, 2, 0);
+                               gridPane.getColumnConstraints().addAll(lColumnValue, lColumnArrow, lColumnArrow);
+                       }
+                       if (lArrowPosition == ArrowPosition.SPLIT)
+                       {
+                               // construct a gridpane: one row, three columns: arrow, value, arrow
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(decrementArrow, 0, 0);
+                               gridPane.add(valueGroup, 1, 0);
+                               gridPane.add(incrementArrow, 2, 0);
+                               gridPane.getColumnConstraints().addAll(lColumnArrow, lColumnValue, lColumnArrow);
+                       }
+               }
+               if (lArrowDirection == ArrowDirection.VERTICAL)
+               {
+                       if (lArrowPosition == ArrowPosition.LEADING)
+                       {
+                               // construct a gridpane: two rows, two columns: arrows on top, value
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(incrementArrow, 0, 0);
+                               gridPane.add(decrementArrow, 0, 1);
+                               gridPane.add(valueGroup, 1, 0, 1, 2);
+                               gridPane.getColumnConstraints().addAll(lColumnArrow, lColumnValue); 
+                               gridPane.getRowConstraints().addAll(lRowArrow, lRowArrow);
+                       }
+                       if (lArrowPosition == ArrowPosition.TRAILING)
+                       {
+                               // construct a gridpane: two rows, two columns: value, arrows on top
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(valueGroup, 0, 0, 1, 2);
+                               gridPane.add(incrementArrow, 1, 0);
+                               gridPane.add(decrementArrow, 1, 1);
+                               gridPane.getColumnConstraints().addAll(lColumnValue, lColumnArrow); 
+                               gridPane.getRowConstraints().addAll(lRowArrow, lRowArrow);
+                       }
+                       if (lArrowPosition == ArrowPosition.SPLIT)
+                       {
+                               // construct a gridpane: three rows, one columns: arrow, value, arrow
+                               gridPane.setHgap(3);
+                               gridPane.setVgap(0);
+                               gridPane.add(incrementArrow, 0, 0);
+                               gridPane.add(valueGroup, 0, 1);
+                               gridPane.add(decrementArrow, 0, 2);
+                               gridPane.getColumnConstraints().addAll(lColumnValue); 
+                               gridPane.getRowConstraints().addAll(lRowArrow, lRowValue, lRowArrow);
+                       }
+               }
+       }
+       
+       /**
+        * Set the CSS according to the direction of the arrows, so the correct arrows are shown
+        */
+       private void setArrowCSS()
+       {
+               if (getSkinnable().getArrowDirection().equals(ListSpinner.ArrowDirection.HORIZONTAL))
+               {
+                       decrementArrow.getStyleClass().add("left-arrow");
+                       incrementArrow.getStyleClass().add("right-arrow");
+               }
+               else
+               {
+                       decrementArrow.getStyleClass().add("down-arrow");
+                       incrementArrow.getStyleClass().add("up-arrow");
+               }
+       }
+}
diff --git a/DuskZ/src/jfxtras/labs/scene/control/ListSpinner.java b/DuskZ/src/jfxtras/labs/scene/control/ListSpinner.java
new file mode 100644 (file)
index 0000000..457c238
--- /dev/null
@@ -0,0 +1,613 @@
+/**
+ * Copyright (c) 2011, JFXtras
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of the <organization> nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package jfxtras.labs.scene.control;
+
+import java.util.Arrays;
+
+import javafx.beans.property.ObjectProperty;
+import javafx.beans.property.SimpleObjectProperty;
+import javafx.beans.value.ChangeListener;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ListChangeListener;
+import javafx.collections.ObservableList;
+import javafx.event.Event;
+import javafx.event.EventHandler;
+import javafx.event.EventTarget;
+import javafx.event.EventType;
+import javafx.geometry.Pos;
+import javafx.scene.Node;
+import javafx.scene.control.Control;
+import javafx.scene.control.Label;
+import javafx.util.Callback;
+import javafx.util.StringConverter;
+
+/**
+ * This is a spinner, showing one value at a time from a list.
+ * This value is set and retrieved from the value property.
+ * Basically a spinner shows a list of values and can do "next" or "previous" on this.
+ * 
+ * A spinner can be editable, the user can then type a value instead of selecting it.
+ * If the value exists in the list, the spinner will simply jump to it. 
+ * If the value does not exist, if defined the AddCallback is called.
+ * - If the AddCallback returns null, spinner will only refresh the current index.
+ * - If the AddCallback returns an Integer, spinner will jump to that index (usually the index where the new value was added).   
+ * 
+ * http://openjdk.java.net/projects/openjfx/ux/spinner/index.html
+ * 
+ * You can style the text in the control using CSS like so:
+ * .ListSpinner .value { 
+ *     -fx-font-weight: bold;
+ * }
+ * 
+ * The "value" class applies to the text in both readonly and editable spinners. Use "readonly" or "editable" to style either mode specifically.
+ *    
+ * @author Tom Eugelink
+ */
+public class ListSpinner<T> extends Control
+{
+       // TODO: implement SelectionModel?
+       // ==================================================================================================================
+       // CONSTRUCTOR
+
+       /**
+        */
+       public ListSpinner()
+       {
+               construct();
+       }
+
+       // ------------
+       // model
+       
+       /**
+        * @param items The item list used to populate the spinner.
+        */
+       public ListSpinner(ObservableList<T> items)
+       {
+               construct();
+               setItems(items);
+               first();
+       }
+
+       /**
+        * @param items The item list used to populate the spinner.
+        * @param startValue The initial value of the spinner (one of the items).
+        */
+       public ListSpinner(ObservableList<T> items, T startValue)
+       {
+               construct();
+               setItems(items);
+               setValue(startValue);
+       }
+
+       // ------------
+       // convenience
+       
+       /**
+        * @param list
+        */
+       public ListSpinner(java.util.List<T> list)
+       {
+               this( FXCollections.observableList(list) );
+       }
+
+       /**
+        * @param list
+        */
+       public ListSpinner(T... list)
+       {
+               this( Arrays.asList(list) );
+       }
+
+       /**
+        * @param from
+        * @param to
+        */
+       public ListSpinner(int from, int to)
+       {
+               this( (java.util.List<T>) new ListSpinnerIntegerList(from, to) );
+       }
+
+       /**
+        * @param from
+        * @param to
+        * @param step
+        */
+       public ListSpinner(int from, int to, int step)
+       {
+               this( (java.util.List<T>) new ListSpinnerIntegerList(from, to, step) );
+       }
+
+       // ------------
+       
+       /*
+        * 
+        */
+       private void construct()
+       {
+               // setup the CSS
+               // the -fx-skin attribute in the CSS sets which Skin class is used
+               this.getStyleClass().add(this.getClass().getSimpleName());
+               
+               // react to changes of the value
+               this.valueObjectProperty.addListener(new ChangeListener<T>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends T> property, T oldValue, T newValue)
+                       {
+                               // get the value of the new index
+                               int lIdx = getItems().indexOf(newValue);
+                               
+                               // set the value
+                               if (ListSpinner.equals(indexObjectProperty.getValue(), lIdx) == false)
+                               {
+                                       indexObjectProperty.setValue(lIdx);
+                               }
+                       }
+               });
+               
+               // react to changes of the index
+               this.indexObjectProperty.addListener(new ChangeListener<Integer>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends Integer> property, Integer oldIndex, Integer newIndex)
+                       {
+                               // get the value of the new index
+                               T lValue = newIndex < 0 ? null : getItems().get(newIndex);
+                               
+                               // set the value
+                               if (ListSpinner.equals(valueObjectProperty.getValue(), lValue) == false)
+                               {
+                                       valueObjectProperty.setValue(lValue);
+                               }
+                       }
+               });
+               
+               // react to changes of the items
+               this.itemsObjectProperty.addListener(new ChangeListener<ObservableList<T>>()
+               {
+                       @Override
+                       public void changed(ObservableValue<? extends ObservableList<T>> property, ObservableList<T> oldList, ObservableList<T> newList)
+                       {
+                               if (oldList != null) oldList.removeListener(listChangeListener);
+                               if (newList != null) newList.addListener(listChangeListener);
+                       }
+               });
+       }
+       
+       /*
+        * react to observable list changes
+        * TODO: what is sticky, index or value? Now: index
+        */
+       private ListChangeListener<T> listChangeListener = new ListChangeListener<T>()
+       {
+               @Override
+               public void onChanged(javafx.collections.ListChangeListener.Change<? extends T> change)
+               {
+                       // get current index
+                       int lIndex = getIndex();
+                       
+                       // is it still valid?
+                       if (lIndex >= getItems().size()) 
+                       {
+                               lIndex = getItems().size() - 1;
+                               setIndex(lIndex);
+                               return;
+                       }
+                       
+                       // (re)set the value of the index
+                       valueObjectProperty.setValue( getItems().get(lIndex) );
+               }
+       };
+
+       /**
+        * Return the path to the CSS file so things are setup right
+        */
+       @Override protected String getUserAgentStylesheet()
+       {
+               return this.getClass().getResource("/jfxtras/labs/internal/scene/control/" + this.getClass().getSimpleName() + ".css").toString();
+       }
+       
+       // ==================================================================================================================
+       // PROPERTIES
+       
+       /** Value: */
+       public ObjectProperty<T> valueProperty() { return this.valueObjectProperty; }
+       final private ObjectProperty<T> valueObjectProperty = new SimpleObjectProperty<T>(this, "value", null)
+       {
+               public void set(T value)
+               {
+                       if (getItems().indexOf(value) < 0) throw new IllegalArgumentException("Value does not exist in the list: " + value); 
+                       super.set(value);
+               }
+       };
+       // java bean API
+       public T getValue() { return this.valueObjectProperty.getValue(); }
+       public void setValue(T value) { this.valueObjectProperty.setValue(value); }
+       public ListSpinner<T> withValue(T value) { setValue(value); return this; }
+       
+       /** Index: */
+       public ObjectProperty<Integer> indexProperty() { return this.indexObjectProperty; }
+       final private ObjectProperty<Integer> indexObjectProperty = new SimpleObjectProperty<Integer>(this, "index", null)
+       {
+               public void set(Integer value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for index");
+                       if (value >= getItems().size()) throw new IllegalArgumentException("Index out of bounds: " + value + ", valid values are 0-" + (getItems().size() - 1)); 
+                       super.set(value);
+               }
+       };
+       public Integer getIndex() { return this.indexObjectProperty.getValue(); }
+       public void setIndex(Integer value) { this.indexObjectProperty.setValue(value); }
+       public ListSpinner<T> withIndex(Integer value) { setIndex(value); return this; }
+       
+       /** Cyclic: */
+       public ObjectProperty<Boolean> cyclicProperty() { return this.cyclicObjectProperty; }
+       final private ObjectProperty<Boolean> cyclicObjectProperty = new SimpleObjectProperty<Boolean>(this, "cyclic", false)
+       {
+               public void set(Boolean value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for cyclic");
+                       super.set(value);
+               }
+       };
+       public Boolean isCyclic() { return this.cyclicObjectProperty.getValue(); }
+       public void setCyclic(Boolean value) { this.cyclicObjectProperty.setValue(value); }
+       public ListSpinner<T> withCyclic(Boolean value) { setCyclic(value); return this; }
+
+       /** Editable: */
+       public ObjectProperty<Boolean> editableProperty() { return this.editableObjectProperty; }
+       final private ObjectProperty<Boolean> editableObjectProperty = new SimpleObjectProperty<Boolean>(this, "editable", false)
+       {
+               public void set(Boolean value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for editable");
+                       super.set(value);
+               }
+       };
+       public Boolean isEditable() { return this.editableObjectProperty.getValue(); }
+       public void setEditable(Boolean value) { this.editableObjectProperty.setValue(value); }
+       public ListSpinner<T> withEditable(Boolean value) { setEditable(value); return this; }
+
+       /** Postfix: */
+       public ObjectProperty<String> postfixProperty() { return this.postfixObjectProperty; }
+       final private ObjectProperty<String> postfixObjectProperty = new SimpleObjectProperty<String>(this, "postfix", "");
+       public String getPostfix() { return this.postfixObjectProperty.getValue(); }
+       public void setPostfix(String value) { this.postfixObjectProperty.setValue(value); }
+       public ListSpinner<T> withPostfix(String value) { setPostfix(value); return this; }
+
+       /** Prefix: */
+       public ObjectProperty<String> prefixProperty() { return this.prefixObjectProperty; }
+       final private ObjectProperty<String> prefixObjectProperty = new SimpleObjectProperty<String>(this, "prefix", "");
+       public String getPrefix() { return this.prefixObjectProperty.getValue(); }
+       public void setPrefix(String value) { this.prefixObjectProperty.setValue(value); }
+       public ListSpinner<T> withPrefix(String value) { setPrefix(value); return this; }
+
+       /** Items: */
+       public ObjectProperty<ObservableList<T>> itemsProperty() { return this.itemsObjectProperty; }
+       final private ObjectProperty<ObservableList<T>> itemsObjectProperty = new SimpleObjectProperty<ObservableList<T>>(this, "items", null)
+       {
+               public void set(ObservableList<T> value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for items");
+                       super.set(value);
+               }
+       };
+       public ObservableList<T> getItems() { return this.itemsObjectProperty.getValue(); }
+       public void setItems(ObservableList<T> value) { this.itemsObjectProperty.setValue(value); }
+       public ListSpinner<T> withItems(ObservableList<T> value) { setItems(value); return this; }
+
+       /** CellFactory: */
+       public ObjectProperty<Callback<ListSpinner<T>, Node>> cellFactoryProperty() { return this.cellFactoryObjectProperty; }
+       final private ObjectProperty<Callback<ListSpinner<T>, Node>> cellFactoryObjectProperty = new SimpleObjectProperty<Callback<ListSpinner<T>, Node>>(this, "cellFactory", new DefaultCellFactory());
+       public Callback<ListSpinner<T>, Node> getCellFactory() { return this.cellFactoryObjectProperty.getValue(); }
+       public void setCellFactory(Callback<ListSpinner<T>, Node> value) { this.cellFactoryObjectProperty.setValue(value); }
+       public ListSpinner<T> withCellFactory(Callback<ListSpinner<T>, Node> value) { setCellFactory(value); return this; }
+
+       /** StringConverter<T>: */
+       public ObjectProperty<StringConverter<T>> stringConverterProperty() { return this.stringConverterObjectProperty; }
+       final private ObjectProperty<StringConverter<T>> stringConverterObjectProperty = new SimpleObjectProperty<StringConverter<T>>(this, "stringConverter", new DefaultStringConverter());
+       public StringConverter<T> getStringConverter() { return this.stringConverterObjectProperty.getValue(); }
+       public void setStringConverter(StringConverter<T> value) { this.stringConverterObjectProperty.setValue(value); }
+       public ListSpinner<T> withStringConverter(StringConverter<T> value) { setStringConverter(value); return this; }
+
+       /** ArrowDirection: */
+       public ObjectProperty<ArrowDirection> arrowDirectionProperty() { return this.arrowDirectionObjectProperty; }
+       final private ObjectProperty<ArrowDirection> arrowDirectionObjectProperty = new SimpleObjectProperty<ArrowDirection>(this, "arrowDirection", ArrowDirection.HORIZONTAL)
+       {
+               public void set(ArrowDirection value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for arrowDirection");
+                       super.set(value);
+               }
+       };
+       public ArrowDirection getArrowDirection() { return this.arrowDirectionObjectProperty.getValue(); }
+       public void setArrowDirection(ArrowDirection value) { this.arrowDirectionObjectProperty.setValue(value); }
+       public ListSpinner<T> withArrowDirection(ArrowDirection value) { setArrowDirection(value); return this; }
+       public enum ArrowDirection {VERTICAL, HORIZONTAL}
+       
+       /** ArrowPosition: */
+       public ObjectProperty<ArrowPosition> arrowPositionProperty() { return this.arrowPositionObjectProperty; }
+       final private ObjectProperty<ArrowPosition> arrowPositionObjectProperty = new SimpleObjectProperty<ArrowPosition>(this, "arrowPosition", ArrowPosition.TRAILING)
+       {
+               public void set(ArrowPosition value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for arrowPosition");
+                       super.set(value);
+               }
+       };                      
+       public ArrowPosition getArrowPosition() { return this.arrowPositionObjectProperty.getValue(); }
+       public void setArrowPosition(ArrowPosition value) { this.arrowPositionObjectProperty.setValue(value); }
+       public ListSpinner<T> withArrowPosition(ArrowPosition value) { setArrowPosition(value); return this; }
+       public enum ArrowPosition {LEADING, TRAILING, SPLIT}
+       
+       /** Alignment: only applicable in non edit mode */
+       public ObjectProperty<Pos> alignmentProperty() { return this.alignmentObjectProperty; }
+       final private ObjectProperty<Pos> alignmentObjectProperty = new SimpleObjectProperty<Pos>(this, "alignment", Pos.CENTER_LEFT)
+       {
+               public void set(Pos value)
+               {
+                       if (value == null) throw new NullPointerException("Null not allowed as the value for alignment");
+                       super.set(value);
+               }
+       };                      
+       public Pos isAlignment() { return this.alignmentObjectProperty.getValue(); }
+       public void setAlignment(Pos value) { this.alignmentObjectProperty.setValue(value); }
+       public ListSpinner<T> withAlignment(Pos value) { setAlignment(value); return this; }
+
+       /** AddCallback: */
+       public ObjectProperty<Callback<T, Integer>> addCallbackProperty() { return this.addCallbackObjectProperty; }
+       final private ObjectProperty<Callback<T, Integer>> addCallbackObjectProperty = new SimpleObjectProperty<Callback<T, Integer>>(this, "addCallback", null);
+       public Callback<T, Integer> getAddCallback() { return this.addCallbackObjectProperty.getValue(); }
+       public void setAddCallback(Callback<T, Integer> value) { this.addCallbackObjectProperty.setValue(value); }
+       public ListSpinner<T> withAddCallback(Callback<T, Integer> value) { setAddCallback(value); return this; }
+
+       // ==================================================================================================================
+       // StringConverter
+       
+       /**
+        * A string converter that does a simple toString, but cannot convert to an object
+        * @see org.jfxextras.util.StringConverterFactory 
+        */
+       class DefaultStringConverter extends StringConverter<T>
+       {
+               @Override
+               public T fromString(String string)
+               {
+                       throw new IllegalStateException("No StringConverter is set. An editable Spinner must have a StringConverter to be able to render and parse the value.");
+               }
+
+               @Override
+               public String toString(T value)
+               {
+                       return value == null ? "" : value.toString();
+               }
+       }
+       
+       // ==================================================================================================================
+       // CellFactory
+       
+       /**
+        * Default cell factory
+        */
+       class DefaultCellFactory implements Callback<ListSpinner<T>, Node>
+       {
+               private Label label = null;
+               
+               @Override
+               public Node call(ListSpinner<T> spinner)
+               {
+                       // get value
+                       T lValue = spinner.getValue();
+                       
+                       // label not yet created
+                       if (this.label == null) 
+                       {
+                               this.label = new Label();
+                       }
+                       this.label.setText( lValue == null ? "" : spinner.getPrefix() + getStringConverter().toString(lValue) + spinner.getPostfix() );
+                       return this.label;
+               }
+       };
+       
+       // ==================================================================================================================
+       // EVENTS
+       
+       /** OnCycle: */
+       public ObjectProperty<EventHandler<CycleEvent>> onCycleProperty() { return iOnCycleObjectProperty; }
+       final private ObjectProperty<EventHandler<CycleEvent>> iOnCycleObjectProperty = new SimpleObjectProperty<EventHandler<CycleEvent>>(null);
+       // java bean API
+       public EventHandler<CycleEvent> getOnCycle() { return iOnCycleObjectProperty.getValue(); }
+       public void setOnCycle(EventHandler<CycleEvent> value) { iOnCycleObjectProperty.setValue(value); }
+       public ListSpinner<T> withOnCycle(EventHandler<CycleEvent> value) { setOnCycle(value); return this; }
+       final static public String ONCYCLE_PROPERTY_ID = "onCycle";
+       
+       /**
+        * CycleEvent 
+        */
+       static public class CycleEvent extends Event
+       {
+               /**
+                * 
+                */
+               public CycleEvent()
+               {
+                       super(new EventType<CycleEvent>());
+               }
+
+               /**
+                * 
+                * @param source
+                * @param target
+                */
+               public CycleEvent(Object source, EventTarget target)
+               {
+                       super(source, target, new EventType<CycleEvent>());
+               }
+               
+               public Object getOldIdx() { return this.oldIdx; }
+               private Object oldIdx;
+               
+               public Object getNewIdx() { return this.newIdx; }
+               private Object newIdx;
+               
+               
+               public boolean cycledDown() { return cycleDirection == CycleDirection.TOP_TO_BOTTOM; }
+               public boolean cycledUp() { return cycleDirection == CycleDirection.BOTTOM_TO_TOP; }
+               CycleDirection cycleDirection;
+       }
+       
+       /**
+        * we're cycling, fire the event
+        */
+       public void fireCycleEvent(CycleDirection cycleDirection)
+       {
+               EventHandler<CycleEvent> lCycleEventHandler = getOnCycle();
+               if (lCycleEventHandler != null)
+               {
+                       CycleEvent lCycleEvent = new CycleEvent();
+                       lCycleEvent.cycleDirection = cycleDirection;
+                       lCycleEventHandler.handle(lCycleEvent);
+               }
+       }
+       static public enum CycleDirection { TOP_TO_BOTTOM, BOTTOM_TO_TOP }
+       
+       
+       // ==================================================================================================================
+       // BEHAVIOR
+
+       /**
+        * 
+        */
+       public void first()
+       {
+               // nothing to do
+               if (getItems() == null || getItems().size() == 0) return;
+               
+               // set the new index (this will update the value)
+               indexObjectProperty.setValue(0);
+       }
+       
+       /**
+        * 
+        */
+       public void decrement()
+       {
+               // nothing to do
+               if (getItems() == null || getItems().size() == 0) return;
+               
+               // get the current index
+               int lOldIdx = this.indexObjectProperty.getValue();
+                                       
+               // get the previous index (usually current - 1)
+               int lIdx = lOldIdx - 1;
+               
+               // if end
+               if (lIdx < 0)
+               {
+                       // if we're not cyclic
+                       if (isCyclic() != null && isCyclic().booleanValue() == false)
+                       {
+                               // do nothing
+                               return;
+                       }
+                       
+                       // cycle to the other end: get the last value
+                       lIdx = getItems().size() - 1;
+                       
+                       // notify listener that we've cycled
+                       fireCycleEvent(CycleDirection.BOTTOM_TO_TOP);
+               }
+
+               // set the new index (this will update the value)
+               indexObjectProperty.setValue(lIdx);
+       }
+       
+       /**
+        * 
+        */
+       public void increment()
+       {
+               // nothing to do
+               if (getItems() == null || getItems().size() == 0) return;
+               
+               // get the current index
+               int lOldIdx = this.indexObjectProperty.getValue();
+               
+               // get the next index (usually current + 1)
+               int lIdx = lOldIdx + 1;
+               
+               // if null is return, there is no next index (usually current + 1)
+               if (lIdx >= getItems().size())
+               {
+                       // if we're not cyclic
+                       if (isCyclic() != null && isCyclic().booleanValue() == false)
+                       {
+                               // do nothing
+                               return;
+                       }
+                       
+                       // cycle to the other end: get the first value
+                       lIdx = 0;
+                       
+                       // notify listener that we've cycled
+                       fireCycleEvent(CycleDirection.TOP_TO_BOTTOM);
+               }
+               
+               // set the new index (this will update the value)
+               indexObjectProperty.setValue(lIdx);
+       }
+
+       /**
+        * Get the last index; if the data provide is endless, this method mail fail!
+        */
+       public void last()
+       {
+               // nothing to do
+               if (getItems() == null || getItems().size() == 0) return;
+               
+               // set the new index (this will update the value)
+               indexObjectProperty.setValue(getItems().size() - 1);
+       }
+
+       /**
+        * Does a o1.equals(o2) but also checks if o1 or o2 are null.
+        * @param o1
+        * @param o2
+        * @return True if the two values are equal, false otherwise.
+        */
+       static public boolean equals(Object o1, Object o2)
+       {
+               if ( o1 == null && o2 == null ) return true;
+               if ( o1 != null && o2 == null ) return false;
+               if ( o1 == null && o2 != null ) return false;
+               // TODO: compare arrays if (o1.getClass().isArray() && o2.getClass().isArray()) return Arrays.equals( (Object[])o1, (Object[])o2 );             
+               return o1.equals(o2);
+       }
+
+}
diff --git a/DuskZ/src/jfxtras/labs/scene/control/ListSpinnerIntegerList.java b/DuskZ/src/jfxtras/labs/scene/control/ListSpinnerIntegerList.java
new file mode 100644 (file)
index 0000000..e9c50f5
--- /dev/null
@@ -0,0 +1,76 @@
+package jfxtras.labs.scene.control;
+
+/**
+ * Items for Spinner providing an integer range without actually creating a list with all values.
+ */
+public class ListSpinnerIntegerList extends java.util.AbstractList<Integer>
+{
+       /**
+        * 
+        */
+       public ListSpinnerIntegerList()
+       {
+               this( (Integer.MIN_VALUE / 2) + 1, Integer.MAX_VALUE / 2, 1);
+       }
+       
+       /**
+        * 
+        * @param from
+        * @param to
+        */
+       public ListSpinnerIntegerList(int from, int to)
+       {
+               this(from, to, from > to ? -1 : 1);
+       }
+       
+       /**
+        * 
+        * @param from
+        * @param to
+        * @param step
+        */
+       public ListSpinnerIntegerList(int from, int to, int step)
+       {
+               this.from = from;
+               this.size = ((to - from) / step) + 1;
+               if (size < 0) throw new IllegalArgumentException("This results in a negative size: " + from + ", " + to + "," + step);
+               this.step = step;
+       }
+       private int from;
+       private int size;
+       private int step;
+       
+       
+       // ===============================================================================
+       // List interface
+       
+       @Override
+       public Integer get(int index)
+       {
+               if (index < 0) throw new IllegalArgumentException("Index cannot be < 0: " + index);
+               int lValue = this.from + (index * this.step);
+               return lValue;
+       }
+
+       @Override
+       public int indexOf(Object o)
+       {
+               // calculate the index
+               int lValue = ((Integer)o).intValue();
+               int lIndex = (lValue - this.from) / this.step;
+               if (lIndex < 0 || lIndex > size) return -1;
+               
+               // check if that what is at the index matches with out value
+               Integer lValueAtIndex = get(lIndex);
+               if (o.equals(lValueAtIndex) == false) return -1;
+               
+               // found it
+               return lIndex;
+       }
+       
+       @Override
+       public int size()
+       {
+               return this.size;
+       }
+}
\ No newline at end of file